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

Drawing OpenGL primitives


Sometimes in 2D game development we need to make use of good old-fashioned OpenGL primitives. With these we can make minimaps, heads up displays, and special effects like bullet tracers and lightning blasts to name a few. In the following scene I've created a simple figure using all of the primitive drawing functions supplied by Cocos2d as well as one I've tweaked and added.

Getting ready

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

How to do it...

Execute the following code:

/* Create a solid circle */
void ccDrawSolidCircle( CGPoint center, float r, float a, NSUInteger segs, BOOL drawLineToCenter)
{
  //Check to see if  we need to draw a line to the center
  int additionalSegment = 1;
  if (drawLineToCenter)
    additionalSegment++;

  const float coef = 2.0f * (float)M_PI/segs;
  
  GLfloat *vertices = calloc( sizeof(GLfloat)*2*(segs+2), 1);
  if( ! vertices )
    return;

  //Calculate line segments
  for(NSUInteger i=0;i<=segs;i++)
  {
    float rads = i*coef;
    GLfloat j = r * cosf(rads + a) + center.x;
    GLfloat k = r * sinf(rads + a) + center.y;
    
    vertices[i*2] = j * CC_CONTENT_SCALE_FACTOR();
    vertices[i*2+1] =k * CC_CONTENT_SCALE_FACTOR();
  }
  vertices[(segs+1)*2] = center.x * CC_CONTENT_SCALE_FACTOR();
  vertices[(segs+1)*2+1] = center.y * CC_CONTENT_SCALE_FACTOR();
    
  //Draw our solid polygon
  glDisable(GL_TEXTURE_2D);
  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  glDisableClientState(GL_COLOR_ARRAY);
  
  glVertexPointer(2, GL_FLOAT, 0, vertices);  
  glDrawArrays(GL_TRIANGLE_FAN, 0, segs+additionalSegment);
  
  glEnableClientState(GL_COLOR_ARRAY);
  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  glEnable(GL_TEXTURE_2D);  
  
  //Free up memory
  free( vertices );
}

@implementation ShapeLayer

-(void) draw {
  //Set line width.
  glLineWidth(4.0f);
  
  //Set point size
  glPointSize(16);
  
  //Enable line smoothing
  glEnable(GL_LINE_SMOOTH);
    
  //Draw a blue quadratic bezier curve
  glColor4ub(0, 0, 255, 255);
  ccDrawQuadBezier(ccp(100,0), ccp(240,70), ccp(380,0), 10);
    
  //Draw a hollow purple circle
  glColor4ub(255, 0, 255, 255);
  ccDrawCircle(ccp(240,160), 125.0f, 0.0f, 100, NO);
    
  //Draw a solid red lines
  glColor4ub(255, 0, 0, 255);
  ccDrawLine(ccp(170,220), ccp(220,190));
  ccDrawLine(ccp(260,190), ccp(310,220));
  
  //Draw a green point
  glColor4ub(0, 255, 0, 255);
  ccDrawPoint(ccp(200,180));
  ccDrawPoint(ccp(280,180));
  
  //Draw a turquoise solid circle
  glColor4ub(0, 128, 255, 50);
  ccDrawSolidCircle(ccp(200,180), 25.0f, 0.0f, 20, NO);
  ccDrawSolidCircle(ccp(280,180), 25.0f, 0.0f, 20, NO);
  
  //Draw a brown hollow circle
  glColor4ub(64,32, 0, 255);
  ccDrawCircle(ccp(200,180), 25.0f, 0.0f, 100, NO);
  ccDrawCircle(ccp(280,180), 25.0f, 0.0f, 100, NO);
  
  //Draw brown lines
  glColor4ub(64,32, 0, 255);
  ccDrawLine(ccp(225,180), ccp(255,180));
  ccDrawLine(ccp(305,180), ccp(370,160));
  ccDrawLine(ccp(175,180), ccp(110,160));
  
  //Draw an orange polygon
  glColor4ub(255, 128, 0, 255);
  CGPoint vertices[5]={ ccp(230,150),ccp(240,160),ccp(250,150),ccp(245,140),ccp(235,140) };
  ccDrawPoly(vertices, 5, YES);

  //Draw a yellow cubic bezier curve
  glColor4ub(255, 255, 0, 255);
  ccDrawCubicBezier(ccp(170,90), ccp(220,150), ccp(260,50), ccp(320,100), 10);
  
  //Restore original values
  glLineWidth(1);
  glDisable(GL_LINE_SMOOTH);
  glColor4ub(255,255,255,255);
  glPointSize(1);  
}

@end

-(CCLayer*) runRecipe {
  ShapeLayer *layer = [[ShapeLayer alloc] init];
  [layer setPosition:ccp(0,0)];
  [self addChild:layer z:2 tag:0];
    
  return self;
}

How it works...

This recipe shows us how to use each primitive drawing function:

  • Overriding the draw method:

    In order to use OpenGL drawing routines we must override the following method of a CCNode:

      -(void) draw;

    As stated in CCNode.h, overriding this method gives us control of underlying OpenGL drawing routines. The following OpenGL statements are implicit:

    glEnableClientState(GL_VERTEX_ARRAY);
      glEnableClientState(GL_COLOR_ARRAY);
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
      glEnable(GL_TEXTURE_2D);

    To overload this method we create a class named ShapeLayer which inherits from CCLayer, and therefore from CCNode. Once attached to the scene this overridden draw method will be called once every cycle.

  • Primitive drawing functions :

    The following primitive drawing functions are available in Cocos2d:

      void ccDrawPoint( CGPoint point );
    void ccDrawPoints( const CGPoint *points, NSUInteger numberOfPoints );
    void ccDrawLine( CGPoint origin, CGPoint destination );
    void ccDrawPoly( const CGPoint *vertices, NSUInteger numOfVertices, BOOL closePolygon );
    void ccDrawCircle( CGPoint center, float radius, float angle, NSUInteger segments, BOOL drawLineToCenter);
    void ccDrawQuadBezier(CGPoint origin, CGPoint control, CGPoint destination, NSUInteger segments);
    void ccDrawCubicBezier(CGPoint origin, CGPoint control1, CGPoint control2, CGPoint destination, NSUInteger segments);

    On top of all this we have tweaked ccDrawCircle to create ccDrawSolidCircle as follows:

      void ccDrawSolidCircle( CGPoint center, float r, float a, NSUInteger segs, BOOL drawLineToCenter);

    Because we are controlling these OpenGL render calls for each frame this technique works well when used in a real-time minimap. We will explore this in a later recipe.

There's more...

If you are planning to use primitive drawing extensively you may want to consider using the Vertex Buffer Object OpenGL extension . Using the GL functions glGenBuffers, glBindBuffer, and glBufferData you can put vertex and other information into video memory rather than system memory. This can drastically improve performance depending on the situation. For more information view the section Best Practices for Working with Vertex Data in the Apple Developer document OpenGL ES Programming Guide for iOS located at http://developer.apple.com/library/ios/#documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/TechniquesforWorkingwithVertexData/TechniquesforWorkingwithVertexData.html.