Book Image

Cocos2d for iPhone 1 Game Development Cookbook

By : Nathan Burba
Book Image

Cocos2d for iPhone 1 Game Development Cookbook

By: Nathan Burba

Overview of this book

Cocos2d for iPhone is a robust but simple-to-use 2D game framework for iPhone. It is easy to use, fast, flexible, free, and Appstore approved. More than 2500 AppStore games already use it, including many best-seller games. Do you want to take your cocos2d game development skills to the next level and become more professional in cocos2d game design? Cocos2d for iPhone 1 Game Development Cookbook will help you reach that next level. You will find over 100 recipes here that explain everything from the drawing of a single sprite to AI pathfinding and advanced networking. Full working examples are emphasized. Starting with the first chapter, Graphics, you will be taken through every major topic of game development. You will find both simple and complex recipes in the book. Each recipe is either a solution to a common problem (playing video files, accelerometer steering) or a cool advanced technique (3D rendering, textured polygons). This cookbook will have you creating professional quality iOS games quickly with its breadth of working example code.
Table of Contents (15 chapters)
Cocos2d for iPhone 1 Game Development Cookbook
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Rendering a texture-filled polygon


When creating games with large levels it is often easy to run into memory limitations. Large maps also contain repetitive drawing of things like grass, trees, mountains, and so on. This recipe will show you how to efficiently render a polygon that is filled in with a repeated texture. These can be drawn at any size and still only use a small amount of memory and CPU time.

Getting ready

Please refer to the project RecipeCollection01 for full working code of this recipe.

How to do it...

Execute the following code:

#import "Vector3D.h"

//Included for CPP polygon triangulation
#import "triangulate.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

@implementation TexturedPolygon
@synthesize vertices, triangles;

+(id) createWithFile:(NSString*)file withVertices:(NSArray*)verts {
  /*** Create a TexturedPolygon with vertices only. ***/
  /*** Perform polygon trianglulation to get triangles. ***/
  
  //Initialization
  TexturedPolygon *tp = [TexturedPolygon spriteWithFile:file];
  tp.vertices = [[NSMutableArray alloc] init];
  tp.triangles = [[NSMutableArray alloc] init];
  
  //Polygon Triangulation
  Vector2dVector a;
  
  for(int i=0; i<[verts count];i+=1){
    //Add polygon vertices
    [tp.vertices addObject:[verts objectAtIndex:i]];
    
    //Add polygon vertices to triangulation container
    CGPoint vert = [[verts objectAtIndex:i] CGPointValue];
    a.push_back( Vector2d(vert.x, vert.y) );
  }

  //Run triangulation algorithm
  Vector2dVector result;
  Triangulate::Process(a,result);
  
  //Gather all triangles from result container
  int tcount = result.size()/3;
  for (int i=0; i<tcount; i++) {
    const Vector2d &p1 = result[i*3+0];
    const Vector2d &p2 = result[i*3+1];
    const Vector2d &p3 = result[i*3+2];
    
    //Add triangle index
    [tp.triangles addObject: [tp getTriangleIndicesFromPoint1:
    ccp(p1.GetX(),p1.GetY()) point2:ccp(p2.GetX(),p2.GetY())
    point3:ccp(p3.GetX(), p3.GetY())] ];
  }  
  
  //Set texture coordinate information
  [tp setCoordInfo];
  
  return tp;
}

+(id) createWithFile:(NSString*)file withVertices:(NSArray*)verts withTriangles:(NSArray*)tris {
  /*** Create a TexturedPolygon with vertices and triangles given. ***/
  
  //Initialization
  TexturedPolygon *tp = [TexturedPolygon spriteWithFile:file];
  tp.vertices = [[NSMutableArray alloc] init];
  tp.triangles = [[NSMutableArray alloc] init];
    
  //Set polygon vertices
  for(int i=0; i<[verts count];i+=1){
    [tp.vertices addObject:[verts objectAtIndex:i]];
  }

  //Set triangle indices
  for(int i=0; i<[tris count];i+=1){
    [tp.triangles addObject:[tris objectAtIndex:i]];
  }

  //Set texture coordinate information
  [tp setCoordInfo];
  
  return tp;
}

-(Vector3D*) getTriangleIndicesFromPoint1:(CGPoint)p1 point2:(CGPoint)p2 point3:(CGPoint)p3 {
  /*** Convert three polygon vertices to triangle indices ***/
  
  Vector3D* indices = [Vector3D x:-1 y:-1 z:-1];
  
  for(int i=0; i< [vertices count]; i++){
    CGPoint vert = [[vertices objectAtIndex:i] CGPointValue];
    if(p1.x == vert.x and p1.y == vert.y){
      indices.x = i;
    }else if(p2.x == vert.x and p2.y == vert.y){
      indices.y = i;
    }else if(p3.x == vert.x and p3.y == vert.y){
      indices.z = i;
    }
  }

  return indices;
}

-(void) addAnimFrameWithFile:(NSString*)file toArray:(NSMutableArray*)arr {
  /*** For textured polygon animation ***/
  
  ccTexParams params = {GL_NEAREST,GL_NEAREST_MIPMAP_NEAREST,GL_REPEAT,GL_REPEAT};
  CCTexture2D *frameTexture = [[CCTextureCache sharedTextureCache] addImage:file];
  [frameTexture setTexParameters:&params];
  CCSpriteFrame *frame = [CCSpriteFrame frameWithTexture:frameTexture rect:self.textureRect];
  [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFrame:frameTexture name:file];
  [arr addObject:frame];
}

-(void) setCoordInfo {
  /*** Set texture coordinates for each vertex ***/

  if(coords){ free(coords); }
  coords = (ccV2F_T2F*)malloc(sizeof(ccV2F_T2F)*[vertices count]);
  
  for(int i=0;i<[vertices count];i++) {  
    coords[i].vertices.x = [[vertices objectAtIndex:i] CGPointValue].x;
    coords[i].vertices.y = [[vertices objectAtIndex:i] CGPointValue].y;
    
    float atlasWidth = texture_.pixelsWide;
    float atlasHeight = texture_.pixelsHigh;
    
    coords[i].texCoords.u = (coords[i].vertices.x + rect_.origin.x)/ atlasWidth;
    coords[i].texCoords.v = (contentSize_.height - coords[i].vertices.y + rect_.origin.y)/ atlasHeight ;
  }
}

-(void) dealloc
{
  //Release texture coordinates if necessary
  if(coords) free(coords);
  [super dealloc];
}

-(void) draw
{
  /*** This is where the magic happens. Texture and draw all triangles. ***/

  glDisableClientState(GL_COLOR_ARRAY);
  
  glColor4ub( color_.r, color_.g, color_.b, quad_.bl.colors.a);
  
  BOOL newBlend = NO;
  if( blendFunc_.src != CC_BLEND_SRC || blendFunc_.dst != CC_BLEND_DST ) {
    newBlend = YES;
    glBlendFunc( blendFunc_.src, blendFunc_.dst );
  }
  
  glBindTexture(GL_TEXTURE_2D, texture_.name);
  
  unsigned int offset = (unsigned int)coords;
  unsigned int diff = offsetof( ccV2F_T2F, vertices);
  glVertexPointer(2, GL_FLOAT, sizeof(ccV2F_T2F), (void*) (offset + diff));
  diff = offsetof( ccV2F_T2F, texCoords);
  glTexCoordPointer(2, GL_FLOAT, sizeof(ccV2F_T2F), (void*) (offset + diff));
  
  for(int i=0;i<[triangles count];i++){
    Vector3D *tri = [triangles objectAtIndex:i];
    short indices[] = {tri.x, tri.y, tri.z};
    glDrawElements(GL_TRIANGLE_STRIP, 3, GL_UNSIGNED_SHORT, indices);
  }
    
  if(newBlend) { glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST); }
  
  glColor4ub( 255, 255, 255, 255);
  
  glEnableClientState(GL_COLOR_ARRAY);
}
@end


@implementation Ch1_RenderTexturedPolygon

-(CCLayer*) runRecipe {
  CGSize s = [[CCDirector sharedDirector] winSize];
        
  //Set polygon vertices
  CGPoint vertexArr[] = { ccp(248,340), ccp(200,226), ccp(62,202),
  ccp(156,120), ccp(134,2), ccp(250,64), ccp(360,0), ccp(338,128),
  ccp(434,200), ccp(306,230) };
  int numVerts = 10;
  
  NSMutableArray *vertices = [[NSMutableArray alloc] init];
  
  //Add vertices to array
  for(int i=0; i<numVerts; i++){
    [vertices addObject:[NSValue valueWithCGPoint:vertexArr[i]]];
  }
      
  //Note: Your texture size MUST be a product of 2 for this to work.
  //Set texture parameters to repeat  
ccTexParams params = {GL_NEAREST,GL_NEAREST_MIPMAP_NEAREST,GL_REPEAT,GL_REPEAT};
  
  //Create textured polygon
TexturedPolygon *texturedPoly = [TexturedPolygon createWithFile:@"bricks.jpg" withVertices:vertices];
  [texturedPoly.texture setTexParameters:&params];
  texturedPoly.position = ccp(128,128);
  
  //Add textured polygon to scene
  [self addChild:texturedPoly z:1 tag:0];
  
  return self;
}

@end

How it works...

TexturedPolygon takes a given set of vertices and uses a polygon triangulation algorithm to find all triangles contained within the polygon. It then textures and draws these triangles using OpenGL triangles strips.

  • Triangulation:

    Triangulation , depending on the polygon, can be a complex process. This is often performed while a map is loading. For very complex polygons it can be advantageous to perform polygon triangulation during level creation and store triangle indices along with the polygon vertices. This can speed up level load times.

  • Uses:

    Textured polygons have many uses including static map textures and background textures.

  • Performance:

    Using this technique you can efficiently draw polygons of virtually any size. Space requirements rely on the size of each texture used rather that the size of each polygon. To use less space, modify TexturedPolygon to re-use pre-initialized textures.

  • Caveats:

    This technique has a few caveats. The textures used must be square and each side's size must be equal to 2n (16x16, 32x32, 64x64, and so on). Also, textures can only be single files, not sprite frames.

There's more...

This recipe may be your first foray into combining Objective-C and C++ code. This is commonly referred to as Objective-C++. For more information please refer to Apple's official developer documentation Using C++ With Objective-C at http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocCPlusPlus.html.