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 and texturing 3D shapes


As odd as it sounds, sometimes in a 2D game you simply just want to add some simple 3D graphics. Whether you are creating a cool 2D/3D hybrid or a simple 3D game with a 2D HUD, 3D graphics are no easy thing to produce. The complexities of a third dimension often conflict with 2D programming paradigms.

For the sake of simplicity, this recipe will show you how to create a simple colored cube and a simple textured cube. The uses of simple geometry are varied even when making a 2D game. However, more examples including shaders and 3D models are beyond the scope of this book.

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"

@interface Cube3D : CCSprite
{
  Vector3D *translation3D;
  Vector3D *rotation3DAxis;
  GLfloat rotation3DAngle;
  bool drawTextured;
}
@property (readwrite, assign) Vector3D *translation3D;
@property (readwrite, assign) Vector3D *rotation3DAxis;
@property (readwrite, assign) GLfloat rotation3DAngle;
@property (readwrite, assign) bool drawTextured;
-(void) draw;
@end

@implementation Cube3D
@synthesize translation3D,rotation3DAxis,rotation3DAngle,drawTextured;

-(void) draw {
  //Vertices for each side of the cube
  const GLfloat frontVertices[]={ -0.5f,-0.5f,0.5f, 0.5f,-0.5f,0.5f, -0.5f,0.5f,0.5f, 0.5f,0.5f,0.5f};
  const GLfloat backVertices[] = { -0.5f,-0.5f,-0.5f, -0.5f,0.5f,-0.5f, 0.5f,-0.5f,-0.5f, 0.5f,0.5f,-0.5f };
  const GLfloat leftVertices[] = { -0.5f,-0.5f,0.5f, -0.5f,0.5f,0.5f, -0.5f,-0.5f,-0.5f, -0.5f,0.5f,-0.5f };
  const GLfloat rightVertices[] = { 0.5f,-0.5f,-0.5f, 0.5f,0.5f,-0.5f, 0.5f,-0.5f,0.5f, 0.5f,0.5f,0.5f };
  const GLfloat topVertices[] = { -0.5f,0.5f,0.5f, 0.5f,0.5f,0.5f, -0.5f,0.5f,-0.5f, 0.5f,0.5f,-0.5f };
  const GLfloat bottomVertices[] = {-0.5f,-0.5f,0.5f,-0.5f,-0.5f,-0.5f,0.5f,-0.5f,0.5f, 0.5f,-0.5f,-0.5f  };
  
  //Coordinates for our texture to map it to a cube side
  const GLfloat textureCoordinates[] = { 0,0, 1,0, 0,1, 1,1,};
  
  //We enable back face culling to properly set the depth buffer
  glEnable(GL_CULL_FACE);
  glCullFace(GL_BACK);

  //We are not using GL_COLOR_ARRAY
  glDisableClientState(GL_COLOR_ARRAY);
  
  //We disable GL_TEXTURE_COORD_ARRAY if not using a texture
  if(!drawTextured){
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  }
  
  //Replace the current matrix with the identity matrix 
  glLoadIdentity();
  //Translate and rotate
  glTranslatef(translation3D.x, translation3D.y, translation3D.z);
  glRotatef(rotation3DAngle, rotation3DAxis.x, rotation3DAxis.y, rotation3DAxis.z);

  //Bind our texture if neccessary
  if(drawTextured){
    glBindTexture(GL_TEXTURE_2D, texture_.name);
  }
  
  //Here we define our vertices, set our textures or colors and finally draw the cube sides
     glVertexPointer(3, GL_FLOAT, 0, frontVertices);
  if(drawTextured){ glTexCoordPointer(2, GL_FLOAT, 0,  textureCoordinates); }
  else{ glColor4f(1.0f, 0.0f, 0.0f, 1.0f); }
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  
      glVertexPointer(3, GL_FLOAT, 0, backVertices);
  if(drawTextured){ glTexCoordPointer(2, GL_FLOAT, 0,  textureCoordinates); }
  else{ glColor4f(1.0f, 1.0f, 0.0f, 1.0f); }
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  
      glVertexPointer(3, GL_FLOAT, 0, leftVertices);
  if(drawTextured){ glTexCoordPointer(2, GL_FLOAT, 0,  textureCoordinates); }
  else{ glColor4f(1.0f, 0.0f, 1.0f, 1.0f); }
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  
      glVertexPointer(3, GL_FLOAT, 0, rightVertices);
  if(drawTextured){ glTexCoordPointer(2, GL_FLOAT, 0,  textureCoordinates); }
  else{ glColor4f(0.0f, 1.0f, 1.0f, 1.0f); }
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  
      glVertexPointer(3, GL_FLOAT, 0, topVertices);
  if(drawTextured){ glTexCoordPointer(2, GL_FLOAT, 0,  textureCoordinates); }
  else{ glColor4f(0.0f, 1.0f, 0.0f, 1.0f); }
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  
      glVertexPointer(3, GL_FLOAT, 0, bottomVertices);
  if(drawTextured){ glTexCoordPointer(2, GL_FLOAT, 0,  textureCoordinates); }
  else{ glColor4f(0.0f, 0.0f, 1.0f, 1.0f); }
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  
  //We re-enable the default render state
  glEnableClientState(GL_COLOR_ARRAY);
  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  glDisable(GL_CULL_FACE);
  glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}
@end


@interface Ch1_3DCubes {
  Cube3D *cube3d1;
  Cube3D *cube3d2;
}

@implementation Ch1_3DCubes

-(CCLayer*) runRecipe {  
  //Load a textured cube and set initial variables
  cube3d1 = [Cube3D spriteWithFile:@"crate.jpg"];
  cube3d1.translation3D = [Vector3D x:2.0f y:0.0f z:-4.0f];
  cube3d1.rotation3DAxis = [Vector3D x:2.0f y:2.0f z:4.0f];
  cube3d1.rotation3DAngle = 0.0f;
  cube3d1.drawTextured = YES;
  [self addChild:cube3d1 z:3 tag:0];
  
  //Load a colored cube and set initial variables
  cube3d2 = [Cube3D spriteWithFile:@"blank.png"];
  cube3d2.translation3D = [Vector3D x:-2.0f y:0.0f z:-4.0f];
  cube3d2.rotation3DAxis = [Vector3D x:2.0f y:2.0f z:4.0f];
  cube3d2.rotation3DAngle = 0.0f;
  cube3d2.drawTextured = NO;
  [self addChild:cube3d2 z:1 tag:1];
  
  //Schedule cube rotation
  [self schedule:@selector(step:)];
  
  return self;
}

-(void) step:(ccTime)delta {
  cube3d1.rotation3DAngle += 0.5f;
  cube3d2.rotation3DAngle -= 0.5f;
}

@end

How it works...

What we see here is a crash course in OpenGL ES cube rendering with a Cocos2d twist. Like when we drew OpenGL primitives, here we create another CCNode and override its draw method to create more complex OpenGL geometry.

  • Texturing:

    We harness a CCSprite method to load a texture into memory to allow us to bind that texture for 3D drawing. This process is fairly straightforward.

  • Depth testing, sizing, and translation:

    Thanks to Cocos2d's built-in depth testing, cubes will be properly ordered based on the Z property. The translation3D.z value affects the actual size of the cube while its translation3D.x and translation3D.y values affect where it is on the screen proportional to translation3D.z.

There's more...

For more information about 3D graphics, please refer to the recipe Using Cocos3d in Chapter 8, Tips, Tools, and Ports.