SG Bienvenida Cocos2D

70
Slinger studios 2011 Manual del bienvenida Comenzando con cocos2D 1

description

Some quick notes about workign with cocos2d game engine

Transcript of SG Bienvenida Cocos2D

Page 1: SG Bienvenida Cocos2D

Slinger studios 2011

Manual del bienvenidaComenzando con cocos2D

1

Page 2: SG Bienvenida Cocos2D

Slinger studios 2011

FECHA AUTOR MODIFICACION01/09/11 Miguel Alcalde Creación de versión draft del manual

2

Page 3: SG Bienvenida Cocos2D

Slinger studios 2011

Índice de contenidoEstructura de un proyecto Cocos2D......................................................................................................4Tareas básicas del UIAppDelegate........................................................................................................5Managers “singleton” de cocos2d más usados......................................................................................6

CCDirector...................................................................................................................................6CCSpriteFrameCache..................................................................................................................7CCTextureCache..........................................................................................................................7CCActionManager.......................................................................................................................7CCAnimationCache.....................................................................................................................7CCTouchDispatcher.....................................................................................................................7CDAudioManager........................................................................................................................7SimpleAudioEngine.....................................................................................................................8CCScheduler................................................................................................................................8

Jerarquía de clases en cocos2d..............................................................................................................8CCNode............................................................................................................................................8CCScene...........................................................................................................................................8CCLayer............................................................................................................................................9CCSprite..........................................................................................................................................11CCMenu..........................................................................................................................................12CCTransictionScene.......................................................................................................................13CCLabel..........................................................................................................................................13CCAction........................................................................................................................................14CCScheduler...................................................................................................................................16CCAnimation..................................................................................................................................17CCSpriteFrame...............................................................................................................................18

Clases utiles de cocos2D..........................................................................................................................18CCSpriteBatchNode.......................................................................................................................18CCBitmapFontAtlas.......................................................................................................................18CCColorLayer.................................................................................................................................18CCProgressTimer............................................................................................................................19CCRibbon.......................................................................................................................................20CCMotionStreak.............................................................................................................................21CCParticleSystem...........................................................................................................................21SimpleAudioEngine........................................................................................................................24CCCamera.......................................................................................................................................24CCLayerMultiplex..........................................................................................................................24

Herramientas y macros importantes.........................................................................................................24Motores de físicas...........................................................................................................................25

Box2D .......................................................................................................................................26ChipMunk..................................................................................................................................33

Listado de acciones ............................................................................................................................39Posicion..........................................................................................................................................39

3

Page 4: SG Bienvenida Cocos2D

Slinger studios 2011

Escalado..........................................................................................................................................39Rotaciones ......................................................................................................................................39Visibilidad.......................................................................................................................................40Opacidad.........................................................................................................................................40Color...............................................................................................................................................40Grid/TileGrid .................................................................................................................................40Composicion:..................................................................................................................................41Ease.................................................................................................................................................41Otras................................................................................................................................................44

Listado de transiciones de escena........................................................................................................44Fade................................................................................................................................................44Movimiento....................................................................................................................................44Solapamientos.................................................................................................................................44Diapositivas....................................................................................................................................45

Interlineado .........................................................................................................................................45Otros...............................................................................................................................................45

Tips, tricks and code snippets..............................................................................................................45Comproba el tipo de un CCNode....................................................................................................45¿Niveles como CCScene o como CCLayer?..................................................................................45¿Heredar objetos del juego por herencia o por composición?........................................................46Crear animaciones..........................................................................................................................46Animation Helper...........................................................................................................................47Usando Texture Atlas .....................................................................................................................48¿Como hacer un parallax infitnito?.................................................................................................48Cambiar la textura asociada a un CCSprite....................................................................................49¿Crear game object por herencia o por composición?....................................................................49Creacion de un XXXSpriteCache para optimizar rendimiento......................................................50¿Como utilizar el Game center de Apple?......................................................................................50Cocos2D integración con redes sociales.........................................................................................66Modos multijugador en cliente-servidor.........................................................................................66Ads and Analytics...........................................................................................................................66Juegos basados en Tiles..................................................................................................................66Mezclado código Cocos2D y Gl en el método draw de CCNode..................................................69 CCDrawingPrimitives.h para dibujar primitivas...........................................................................70

Estructura de un proyecto Cocos2D

1. cocos2d sources:2. Resources: cosas que no se deben compilar (ver reglas de compilación).

• Default.png: Imagen cuando carga la app.• fps_images.png: Font bitmap atlas.• Icon.png: Icono de app.

4

Page 5: SG Bienvenida Cocos2D

Slinger studios 2011

• Info.plist: settings de la aplicación, incluido las imagenes asociadas.3. Other sources/XXX:

• main.m: Fichero principal mainint main(int argc, char *argv[]) {

NSAutoreleasePool *pool = [NSAutoreleasePool new];int retVal = UIApplicationMain(argc, argv, nil, @"HelloWorldAppDelegate");[pool release];return retVal;

}• Donde UIApplicationMain crea la aplicación y el bucle principal .• Parametro 3º es la clase principal, en caso de nil es el valor de NSNibFile.• Parametro 4º es el ApplicationDelegate.

• xxx.pch: Fichero de cabeceras precompiladas

Tareas básicas del UIAppDelegate.

Gestiona los diferentes estados de la aplicación, recibe mensajes de IOS en determinados monentos relevantes, Por ejemplo:

• applicationDidFinishLaunching: Es cuando la aplicación ha creado los objetos principal y es donde debemos insertar el código de inicilización.

• applicationWillTerminate/applicationDidEnterBacnkground: Por diseño no se llama nunca al dealloc de la clase UIApplicationDelegate, insertar el código del impieza aquí.

• ApplicationDidReceiveMemoryWarning: IOS 4 es multitarea por lo cual debemos compartir la memoria del dispositivo (si 128MB 35-40 MB son disponibles). Este método se llama cuando se alcanzan los umbrales de memoria.

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { [[CCTextureCache sharedTextureCache] removeUnusedTextures]; [[CCDirector sharedDirector] purgeCachedData]; }

En la mayoría de casos el código de inicialización generado por cocos2d nos es suficiente, sin embargo hemos de poner especial atención a:

[[CCDirector sharedDirector] setDeviceOrientation:CCDeviceOrientationLandscapeLeft]; //orientacion inicial[[CCDirector sharedDirector] setAnimationInterval:1.0/60]; //Framerate 1sg/frames (30..60).[[CCDirector sharedDirector] setDisplayFPS:YES]; //Show FPS se actualiza según CC_DIRECTOR_FPS_INTERVAL en ccConfig.h

El dispositivo permite diversas orientaciones:

5

Page 6: SG Bienvenida Cocos2D

Slinger studios 2011

• CCDeviceOrientationPortrait (botón abajo)• CCDeviceOrientationPortraitUpsideDown (botón arriba)• CCDeviceOrientationLandscapeLeft(botón a la derecha)• CCDeviceOrientationLandscapeRight (botón a la izquierda)

Managers “singleton” de cocos2d más usados.

CCDirector* sharedDirector = [CCDirector sharedDirector];CCScheduler* sharedScheduler = [CCScheduler sharedScheduler];CCSpriteFrameCache* sharedCache = [CCSpriteFrameCache sharedSpriteFrameCache];CCTextureCache* sharedTexCache = [CCTextureCache sharedTextureCache];CCActionManager* sharedAction = [CCActionManager sharedManager];CCTouchDispatcher* sharedDispatcher = [CCTouchDispatcher sharedDispatcher];CDAudioManager* sharedManager = [CDAudioManager sharedManager];SimpleAudioEngine* sharedEngine = [SimpleAudioEngine sharedEngine];

CCDirector

Es el cerebro de Cocos2D• Mantiene la configuración.• Maneja las escenas.• Acceso a las vistas (UIView, UIWindow y OpenGL view).• Inicializa el contexto Open GL.

• Habilita los estados GL (por defecto GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY)

• Establece en formato del buffer de color (por defecto RGB565).• Establece la precisionde buffer de profundidad (por defecto es 0).• Establece la orientación (por defcto es portrait).• Establece el modo de alpha blending y depth test.

• Pausa, retoma y finaliza el juego.• Convierte coordenadas entre sistemas (UIKit<->OpenGL).

Es el cerebro de cocos2d, actualmente existen varias implementaciones: •

• CCDisplayLinkDirector basada en CADisplayLink • CCFastDirector, • CCThreadedFastDirector que usa las Cocoa Touch Views • CCTimerDirector con menor rendimiento y consumo de memoria.

Permite definir el tipo de projeccion a usar:• kCCDirectorProjection2D: Projección ortogonal.• KCCDirectorProjection3D: Projeccion 3D (fovy=60º z-near=0.5f z-far=1500). Este es el

valor por defecto.

6

Page 7: SG Bienvenida Cocos2D

Slinger studios 2011

• kCCDirectorProjectionCustom: Se define en el método updateProjection

CCSpriteFrameCache

Gestiona la cache de CCSpriteFrame (textura y las coordenadas de textura asociadas).• Carga la definicion de CCSpriteFrame desde fichero, NSDictiionary o explicitamente.• Implementa la política de uso LRU.

CCTextureCache

Gestiona la cache de texturas (CCTexture2D).• Carga texturas (sincrona y asincrona) desde fichero con extension png/jpg o desde CGImageRef

de Cocoa.• Implementa la política de uso LRU.

CCActionManager

Gestiona las acciones. • Permite parar y reanudar las acciones.

CCAnimationCache

Gestiona las animaciones.

CCTouchDispatcher

Controla los eventos de touch y los redirecciona a todos los listener registrados. Soporta 2 formas de gestionar los eventos (protocol CCTouchDelegateProtocol)

• Tradicional de Cocoa.• ccTouchesBegan:• ccTouchesMoved• ccTouchesEnded• ccTouchesCancelled

• Targeted touch handler: • ccTouchBegan:• ccTouchMoved• ccTouchEnded• ccTouchCancelled

CDAudioManager

Manager para utilizar los dispositivos de audio. • Play de música y efectos.• Gestiona el uso compartida de los recursos.

7

Page 8: SG Bienvenida Cocos2D

Slinger studios 2011

SimpleAudioEngine

Wrapper de CDAudioManager que simplifica su uso.• Play, stop y resume de música y efectos.• Precargar los efectos de sonido.

CCScheduler

Controla el bucle principal de renderizado y los listeners asociados.Permite registrar un listener y asociarles un intervalo de refresco customizado.

Jerarquía de clases en cocos2d.

CCNode

Clase base de todos los nodos de la escena, contiene la posición pero no tiene representación visual.

Algunos atributos importantes:

• tag: sirve para identificar el nodo hay que procurar que sean únicos.

Algunos metodos importantes:

• node: Constructor de clase.

CCNode* childNode = [CCNode node];

• getChildByTag: Retorna un nodo hijo por tag. Por implementación retorna el primero nodo para el tag dado. Es importante hacer los tag como UID.

CCNode* retrievedNode = [myNode getChildByTag:123];

• addChildNode: Añadir un nodo hijo

[myNode addChild:childNode z:0 tag:123];

• removeChildByTag: Elimina un nodo por tag si cleanup se paran todas las acciones..

[myNode removeChild:retrievedNode];

• removeAllChildrenWithCleanup: Elimina todos los hijos y si procede para las acciones.

[myNode removeAllChildrenWithCleanup:YES];

• removeFromParentAndCleanup. Detach nodo de su padre con cleanup.

[myNode removeFromParentAndCleanup:YES];

CCScene

Nodo root del árbol de la escena. Es puramente una clase sin representación visual que actua como elemento abstracto. Típicamente se obtiene a través de patrón de diseño (buider method = método de clase scene) en una clase CCLayer de cocos2d.

• Patron factory más usado en proyectos cocos2d

8

Page 9: SG Bienvenida Cocos2D

Slinger studios 2011

+(id) scene

{

CCScene *scene = [CCScene node];

id node = [HelloWorld node]; //Constructor clase. equivalente a alloc->init->autorelease

[scene addChild:node];

return scene;

}

//applicationDidFinishedLaunching

[[CCDirector sharedDirector] replaceScene:[MyLayer scene];

Las escenas son mostradas por la clase CCDirector en diferentes formas.

• [CCDirector runScene]: Muestra una escena, en caso de existir una la ignora (sólo llamar a este método la primera vex)

• [CCDirector replaceScene]: En caso de existir una escena llama al método removeAll para hacer el cleanup (para todas las acciones) , sustituye por la nueve escena y libera la anterior

• [pushScene/popScene]: Funciona como una pila no se liberan las escenas.

Existe una regla de oro que es la de nunca llamar a estos métodos dentro del init de la escena puesto que produce un crash.

CCLayer

Agrupación de nodos, gestiona los eventos desde la interface de usuario: acelerometro y eventos de toque. Es importante minimizar en número de clases CCLayer que reciben los eventos de toque y acelerometro.

Los eventos viene en coordenadas de pantalla la clase CCDirector contiene los métodos para convertir a coordenadas mundo.

-(CGPoint) locationFromTouches:(NSSet *)touches

{

UITouch *touch = [touches anyObject];

CGPoint touchLocation = [touch locationInView: [touch view]];

return [[CCDirector sharedDirector] convertToGL:touchLocation];

}

Algunos atributos importantes:

9

Page 10: SG Bienvenida Cocos2D

Slinger studios 2011

• isTouchEnabled: habilita los eventos de toque.

• isAccelerometerEnabled: Habilitar los eventos del acelerometro.

Algunos metodos importantes:

• Eventos de toque (modelo tradicional):

//Called when a finger just begin touching the screen

-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent*)event

//Called whenever the finger moves on the screen:

-(void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent*)event

//Called when a finger is lifted off the screen:

-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent*)event

//Called to cancel a touch:

-(void) ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent*)event

• Eventos de toque (alternativa): Se pasa un único evento. Para ello es precido registra el manejador.

-(void) registerWithTouchDispatcher

{

[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self

priority:INT_MIN+1 swallowsTouches:YES];

}

-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {}

-(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {}

-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {}

-(void) ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event {}

• Eventos del accelometro.

-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration

{

// controls how quickly velocity decelerates (lower = quicker to change direction)

float deceleration = 0.4f;

// determines how sensitive the accelerometer reacts (higher = more sensitive)

10

Page 11: SG Bienvenida Cocos2D

Slinger studios 2011

float sensitivity = 6.0f;

// how fast the velocity can be at most

float maxVelocity = 100;

// adjust velocity based on current accelerometer acceleration

playerVelocity.x = playerVelocity.x * deceleration + acceleration.x * sensitivity;

// we must limit the maximum velocity of the player sprite, in both directions

if (playerVelocity.x > maxVelocity)

{

playerVelocity.x = maxVelocity;

}

else if (playerVelocity.x < - maxVelocity)

{

playerVelocity.x = - maxVelocity;

}

}

CCSprite

Clase usada para mostrar una textura por pantalla.

Algunos atributos importantes:

• anchorPoint: Por defecto está situado en el centro de la textura. El anchor point no cambia la posicion del nodo, simplemente define el desplazamiento de la textura. Por ejemplo si ponemos el valor a (0,0) alienamos la textura con el nodo. Es mejor dejarlo por defecto en caso de usar rotaciones.

• anchorPointInPixels: devuelve el valor del anchor point en pixel de pantalla.

Algunos metodos importantes

• spriteWithFile: Método de clase para crear un CCSprite dado un fichero de textura.

CCSprite* sprite = [CCSprite spriteWithFile:@”Default.png”];

CGSize screenSize = [[CCDirector sharedDirector] winSize];

float imageHeight = [player texture].contentSize.height;

player.position = CGPointMake(screenSize.width / 2, imageHeight / 2);

11

Page 12: SG Bienvenida Cocos2D

Slinger studios 2011

CCMenu

La clase CCMenu sólo admite nodos de clase CCMenuItem como hijos.Los nodos CCMenuItem pueden ser de diverso tipo:

• CCMenuItemFont: Basados en fuentes TrueType.

// set CCMenuItemFont default properties

[CCMenuItemFont setFontName:@"Helvetica-BoldOblique"];

[CCMenuItemFont setFontSize:26];

// create a few labels with text and selector

CCMenuItemFont* item1 = [CCMenuItemFont itemFromString:@"Go Back!" target:self selector:@selector(menuItem1Touched:)];

• CCMenuItemSprite: Basados en imagenes

// create a menu item using existing sprites

CCSprite* normal = [CCSprite spriteWithFile:@"Icon.png"];

normal.color = ccRED;

CCSprite* selected = [CCSprite spriteWithFile:@"Icon.png"];

selected.color = ccGREEN;

CCMenuItemSprite* item2 = [CCMenuItemSprite itemFromNormalSprite:normal

selectedSprite:selected target:self selector:@selector(menuItem2Touched:)];

• CCMenuItemToggle: Tipo communtador.

// create a toggle item using two other menu items (toggle works with images, too)

[CCMenuItemFont setFontName:@"STHeitiJ-Light"];

[CCMenuItemFont setFontSize:18];

CCMenuItemFont* toggleOn = [CCMenuItemFont itemFromString:@"I'm ON!"];

CCMenuItemFont* toggleOff = [CCMenuItemFont itemFromString:@"I'm OFF!"];

CCMenuItemToggle* item3 = [CCMenuItemToggle itemWithTarget:self

selector:@selector(menuItem3Touched:) items:toggleOn, toggleOff, nil];

Creación de un menú a partir de los items CmenuItem.

// create the menu using the items

CCMenu* menu = [CCMenu menuWithItems:item1, item2, item3, nil];

menu.position = CGPointMake(size.width / 2, size.height / 2);

[self addChild:menu];

// aligning is important, so the menu items don’t occupy the same location

12

Page 13: SG Bienvenida Cocos2D

Slinger studios 2011

[menu alignItemsVerticallyWithPadding:40];

CCTransictionScene

Inserta un efecto de transición entre escenas. Esta clase deriva de CCScene por lo que puede ser mostrada por los mismo métodos de la clase CCDirector (runScene, replaceScene y pushScene).

CCFadeTransition* tran = [CCFadeTransition transitionWithDuration:1 scene:[HelloWorld scene] withColor:ccWHITE];

[[CCDirector sharedDirector] replaceScene:tran];

Algunas transiciones relevantes:

• CCFadeTransiction: Fade a un color específico.

• CCFadeTRTransiction:Flip para revelar nueva escena.

• CCJumpZoomTransiction: La escena salta y se hace más pequeña.

• CCMoveInLTransiction:Movimiento de la escena fuera de la cámara.

• CCOrientedTransictionScene:Flip avanzado.

• CCPageTurnTransitcion: Efecto girar página.

• CCRotoZoomTransiction: Escena rota y se hace más pequeña.

• CCShrinkGrowTransiction: Escena decrece y la nueva crece

• CCSlideInTransiction: La nueva se desliza por encima.

• CCSplitColsTransiction: Columnas de la antigua en un sentido, de la nueva en el otro.

• CCTurnOffTilesTransiction: Tiles aleatorio.

CCLabel

Es la forma más sencilla de mostrar texto en pantalla.Se genera una textura, por esta razón hay que tener cuidado con las actualización constantes del contenido pues puede llegar a ralentizar el programa.CCLabel* label = [CCLabel labelWithString:@"text" fontName:@"AppleGothic" fontSize:32];[label setString:@"new text"];// align label to the rightlabel.anchorPoint = CGPointMake(1, 0.5f);// align label to the leftlabel.anchorPoint = CGPointMake(0, 0.5f);// align label to the toplabel.anchorPoint = CGPointMake(0.5f, 1);// align label to the bottomlabel.anchorPoint = CGPointMake(0.5f, 0);

13

Page 14: SG Bienvenida Cocos2D

Slinger studios 2011

CCAction

Modifica la posición y aspecto del un CCNode

• ActionWithDuration: Crear una accion

CCAction* action = [CCBlink actionWithDuration:10 blinks:20];

• runAction: ejecuta la accion creada en el nodo.

[myNode runAction:action];

• getActionByTag: retorna el action por tag dado un nodo.

CCAction* retrievedAction = [myNode getActionByTag:234];

• stopActionByTag: para la accion dado un tag.

[myNode stopActionByTag:234];

• stopAction: para la action dado un puntero.

[myNode stopAction:action];

• stopAllActions: Para todas las acciones.

[myNode stopAllActions];

• reverse: ejecuta la accion en el orden inverso

Acciones repetivivas

CCRotateBy* rotateBy = [CCRotateBy actionWithDuration:2 angle:360];

CCRepeatForever* repeat = [CCRepeatForever actionWithAction:rotateBy];

[myNode runAction:repeat]

;

Acciones Ease (movimientos no lineales)

CCRotateBy* rotateBy = [CCRotateBy actionWithDuration:2 angle:360];

CCRepeatForever* repeat = [CCRepeatForever actionWithAction:rotateBy];

[myNode runAction:repeat];

Existen diferente tipos (curvas a aplicar):

• CCEaseBackIn, CCEaseBackInOut, CCEaseBackOut:

• CCEaseBounceIn, CCEaseBounceInOut, CCEaseBounceOut:

• CCEaseElasticIn, CCEaseElasticInOut, CCEaseElasticOut:

• CCEaseExponentialIn, CCEaseExponentialInOut:

14

Page 15: SG Bienvenida Cocos2D

Slinger studios 2011

• CCEaseExponentialOut:

• CCEaseIn, CCEaseInOut, CCEaseOut:

• CCEaseSineIn, CCEaseSineInOut, CCEaseSineOut: Sinusoidal

Secuencias de acciones

CCTintTo* tint1 = [CCTintTo actionWithDuration:4 red:255 green:0 blue:0];

CCTintTo* tint2 = [CCTintTo actionWithDuration:4 red:0 green:0 blue:255];

CCTintTo* tint3 = [CCTintTo actionWithDuration:4 red:0 green:255 blue:0];

CCSequence* sequence = [CCSequence actions:tint1, tint2, tint3, nil];

[label runAction:sequence];

//You can also use a CCRepeatForever action with the sequence:

CCSequence* sequence = [CCSequence actions:tint1, tint2, tint3, nil];

CCRepeatForever* repeat = [CCRepeatForever actionWithAction:sequence];

[label runAction:repeat];

Acciones instantaneas ( CCInstantAction).

CCCallFunc* func = [CCCallFunc actionWithTarget:self selector:@selector(onCallFunc)];

CCCallFuncN* funcN = [CCCallFuncN actionWithTarget:self

selector:@selector(onCallFuncN:)];

CCCallFuncND* funcND = [CCCallFuncND actionWithTarget:self

selector:@selector(onCallFuncND:data:) data:(void*)self];

CCSequence* seq = [CCSequence actions:tint1, func, tint2, funcN, tint3, funcND, nil];

[label runAction:seq];

-(void) onCallFunc

{

CCLOG(@"end of tint1!");

}

-(void) onCallFuncN:(id)sender

{

CCLOG(@"end of tint2! sender: %@", sender);

}

15

Page 16: SG Bienvenida Cocos2D

Slinger studios 2011

-(void) onCallFuncND:(id)sender data:(void*)data

{

// be careful when casting pointers like this!

// you have to be 100% sure the object is of this type!

CCSprite* sprite = (CCSprite*)data;

CCLOG(@"end of sequence! sender: %@ - data: %@", sender, sprite);

}

CCScheduler

• ScheduleUpdates: Asociar un método al ciclo de renderizado.

-(void) scheduleUpdates

{

[self scheduleUpdate];

}

-(void) update:(ccTime)delta

{

// this method is called every frame

}

• Schedule: Planificar un listener asociado un metodo arbritario.

-(void) scheduleUpdates

{

[self schedule:@selector(updateTenTimesPerSecond:) interval:0.1f];

}

-(void) updateTenTimesPerSecond:(ccTime)delta

{

// this method is called according to its interval, ten times per second

}

• UnscheduleAllSelectors: Elimina todos los listeners de un nodo

[self unscheduleAllSelectors];

• unschedule: Para un listener particular de un nodo

[self unschedule:@selector(updateTenTimesPerSecond:)];

16

Page 17: SG Bienvenida Cocos2D

Slinger studios 2011

• Patron scheduler-once: Planificar una única ejecución

-(void) scheduleUpdates

{

[self schedule:@selector(tenMinutesElapsed:) interval:600];

}

-(void) tenMinutesElapsed:(ccTime)delta

{

// unschedule the current method by using the _cmd keyword

[self unschedule:_cmd];

}

CCAnimation

• AddFrame: Añade un frame ( CCSpriteFrame) a la animación

// create the sprite sheet

CCSpriteSheet *danceSheet = [CCSpriteSheet spriteSheetWithFile:@"grossini_dance_atlas.png"];

[self addChild:danceSheet];

// create the sprite

CCSprite *danceSprite = [CCSprite spriteWithTexture:danceSheet.texture rect:CGRectMake(0, 0, 85, 121)];

[danceSheet addChild:danceSprite];

// create the animation

CCAnimation *danceAnimation = [CCAnimation animationWithName:@"dance" delay:0.1f];

CCSpriteFrame *frame = [CCSpriteFrame frameWithTexture:danceSheet.texture

rect:CGRectMake(x*85,y*121,85,121) offset:ccp(0,0)];

[danceAnimation addFrame:frame];

// create the action

CCAnimate *danceAction = [CCAnimate actionWithAnimation:danceAnimation];

CCRepeatForever *repeat = [CCRepeatForever actionWithAction:danceAction];

// run the action

[danceSprite runAction:repeat]

17

Page 18: SG Bienvenida Cocos2D

Slinger studios 2011

• initWithFrames: Iniciliza la animación desde una array de frames (CCSpriteFrame)

CCSpriteFrame

CCSpriteFrame es una clase que representa la textura y las coordeanas de textura. Es util para modificar la textura asociada a un CCSprite

CCSpriteFrame *frame = [CCSpriteFrame frameWithTexture:texture rect:rect offset:offset];[sprite setDisplayFrame:frame];

• FrameWithTexture/initWithTexture: Crea un CCSpriteFrame desde una CCTexture.

Clases utiles de cocos2D

CCSpriteBatchNode

Permite optimizar el uso de la memoria gráfica de la tarjeta al empaqueta llamadas al renderizado de objetos que comparte una textura (puede ser un atlas). Existen sin embargo algunas limitaciones:

• Todo se pintará sobre la misma Z. Si se necesitan pintar en varios niveles es preciso usar varias clases CCSpriteBatchNode.

• Todos los objetos deben usar la misma textura o texture atlas.

CCSpriteBatchNode* batch = [CCSpriteBatchNode batchNodeWithFile:@"bullet.png"];[self addChild:batch];for (int i = 0; i < 100; i++){ CCSprite* sprite = [CCSprite spriteWithFile:@”bullet.png”]; [batch addChild:bullet];}

CCBitmapFontAtlas

Atlas con los glyphs de las fuentes para un tamaño dado.

scoreLabel = [CCBitmapFontAtlas bitmapFontAtlasWithString:@"0" fntFile:@"bitmapfont.fnt"];

CCColorLayer

Permite cambiar el color de fondo (es un glClearColor de OpenGL). La clase CCLayerGradient deriva de esta pero muestra una capa de color degradada.

// Set background color to magenta. The most unobtrusive color imaginable.CCColorLayer* colorLayer = [CCColorLayer layerWithColor:ccc4(255, 0, 255, 255)];

18

Page 19: SG Bienvenida Cocos2D

Slinger studios 2011

[self addChild:colorLayer z:0];

CCProgressTimer

Permite mostrar un indicador de progreso sobre una imagen con diversas formas.tarta, barra.

// Progress timer is a sprite only partially displayed to visualize some kind of progress.CCProgressTimer* timer = [CCProgressTimer progressWithFile:@"firething.png"];timer.type = kCCProgressTimerTypeRadialCCW;timer.percentage = 0;[self addChild:timer z:1 tag:UILayerTagProgressTimer];// The update is needed for the progress timer.[self scheduleUpdate];

-(void) update:(ccTime)delta{ CCNode* node = [self getChildByTag:UILayerTagProgressTimer]; NSAssert([node isKindOfClass:[CCProgressTimer class]], @"node is not a CCProgressTimer"); // Updates the progress timer CCProgressTimer* timer = (CCProgressTimer*)node; timer.percentage += delta * 10; if (timer.percentage >= 100) { timer.percentage = 0; }}

CCParallaxNode

Permite crear el efecto de parallax

// Load the sprites for each parallax layer, from background to foreground.CCSprite* para1 = [CCSprite spriteWithFile:@"parallax1.png"];CCSprite* para2 = [CCSprite spriteWithFile:@"parallax2.png"];CCSprite* para3 = [CCSprite spriteWithFile:@"parallax3.png"];CCSprite* para4 = [CCSprite spriteWithFile:@"parallax4.png"];// Set the correct offsets depending on the screen and image sizes.para1.anchorPoint = CGPointMake(0, 1);para2.anchorPoint = CGPointMake(0, 1);para3.anchorPoint = CGPointMake(0, 0.6f);para4.anchorPoint = CGPointMake(0, 0);CGPoint topOffset = CGPointMake(0, screenSize.height);CGPoint midOffset = CGPointMake(0, screenSize.height / 2);CGPoint downOffset = CGPointZero;// Create a parallax node and add the sprites to it.CCParallaxNode* paraNode = [CCParallaxNode node];[paraNode addChild:para1 z:1 parallaxRatio:CGPointMake(0.5f, 0)positionOffset:topOffset];[paraNode addChild:para2 z:2 parallaxRatio:CGPointMake(1, 0) positionOffset:topOffset];[paraNode addChild:para3 z:4 parallaxRatio:CGPointMake(2, 0) positionOffset:midOffset];

19

Page 20: SG Bienvenida Cocos2D

Slinger studios 2011

[paraNode addChild:para4 z:3 parallaxRatio:CGPointMake(3, 0) positionOffset:downOffset];[self addChild:paraNode z:0 tag:ParallaxSceneTagParallaxNode];// Move the parallax node to show the parallaxing effect.CCMoveBy* move1 = [CCMoveBy actionWithDuration:5 position:CGPointMake(-160, 0)];CCMoveBy* move2 = [CCMoveBy actionWithDuration:15 position:CGPointMake(160, 0)];CCSequence* sequence = [CCSequence actions:move1, move2, nil];CCRepeatForever* repeat = [CCRepeatForever actionWithAction:sequence];[paraNode runAction:repeat];

CCRibbon

Sirve para pintar siguiento una línea y utilizando una textura. Por ejemplo para simular el efecto de un rastro de pisadas.

-(void) resetRibbon{ // Removes the ribbon and creates a new one. [self removeChildByTag:ParallaxSceneTagRibbon cleanup:YES]; CCRibbon* ribbon = [CCRibbon ribbonWithWidth:32 image:@"spider.png" length:32 color:ccc4(255, 255, 255, 255) fade:0.5f]; [self addChild:ribbon z:5 tag:ParallaxSceneTagRibbon];}

-(CCRibbon*) getRibbon{ CCNode* node = [self getChildByTag:ParallaxSceneTagRibbon]; NSAssert([node isKindOfClass:[CCRibbon class]], @"node is not a CCRibbon"); return (CCRibbon*)node;}

-(void) addRibbonPoint:(CGPoint)point{ CCRibbon* ribbon = [self getRibbon]; [ribbon addPointAt:point width:32];}

-(BOOL) ccTouchBegan:(UITouch*)touch withEvent:(UIEvent *)event{ [self addRibbonPoint:[MultiLayerScene locationFromTouch:touch]]; return YES;}

-(void) ccTouchMoved:(UITouch*)touch withEvent:(UIEvent *)event{ [self addRibbonPoint:[MultiLayerScene locationFromTouch:touch]];}

-(void) ccTouchEnded:(UITouch*)touch withEvent:(UIEvent *)event{ [self resetRibbon];}

20

Page 21: SG Bienvenida Cocos2D

Slinger studios 2011

CCMotionStreak

Wrapper sobre CCRibbon simula el efecto que las pisadas desaparecen lentamente.

-(void) resetMotionStreak{ // Removes the CCMotionStreak and creates a new one. [self removeChildByTag:ParallaxSceneTagRibbon cleanup:YES]; CCMotionStreak* streak = [CCMotionStreak streakWithFade:0.7f minSeg:10 image:@"spider.png" width:32 length:32 color:ccc4(255, 0, 255, 255)]; [self addChild:streak z:5 tag:ParallaxSceneTagRibbon];}-(void) addMotionStreakPoint:(CGPoint)point{ CCMotionStreak* streak = [self getMotionStreak]; [streak.ribbon addPointAt:point width:32];}

CCParticleSystem

Clase usada para representar efectos de partículas. Cocos2D viene con dos implementaciones para esta clase:

• CCPointParticleSystem: Para dispositvos de 1º y 2º generación. Sin emabrgo no se comporta bien en los de 3º, 4º y posteriores debido a los cambios de hardware.

• CCQuadParticleSystem: Funciona perfecto en todos los dispositivos.

La macro QuadParticleSystem ARCH_OPTIMAL_PARTICLE_SYSTEM nos devuelve la clase correcta para nuestro dispositivo.

Para cada efectos de partículas tenemos varios atributos a configurar.

• totalParticles:Número máximo de partículas vivas.

• AutoRemoveOnFinish: El efecto de partículas será eliminado de su nodo padre al terminar.

• EmitterMode: gravity( kCCParticleModeGravity) en este caso las partículas se alejan del centro de gravedad o, radial en cuyo caso rotan alrededor de un círculo.

• Duration: duración en sg o infinito (kCCParticleDurationInfinity).

• EmissionRate: Partículas por segundo.

• Gravity: Valor de la graved

• centerOfGravity: Posicion del centro de gravedad.

• RadialAccel: Aceleración a la cual se alejan del centro. Valores negativos provoca que se emitan por el otro lado.

• RadialAccelVar: Varianza de radialaccel

• speed: Velocidad de la partícula

21

Page 22: SG Bienvenida Cocos2D

Slinger studios 2011

• speedVar: Varianza de speed.

• TangentialAccel: Velocidad tangencial alrededor del centro de gravedad.

• tangentialAccelVar: Varianza de tangetialAccel.

• StartRadius: Posicion inicial desde el centro del círculo.

• StartRadiusVar: Varianza de startRadius.

• EndRadius: Posición final del círculo. Si kCCParticleStartRadiusEqualToEndRadius obtenemos un círculo sin variaciones.

• EndRadiusVar: Varianza endRadius.

• RotatePerSecond: Dirección y velocidad angular.

• RotatePerSecondVar: Varianza de rotatepersecond.

• Position: offset del efecto con respecto al nodo padre.

• PosVar: Varianza de position.

• PositionType: Como debe moverse el efecto de particulas con respecto a los movimientos del nodo padre. Si kCCPositionTypeGrouped le sigue por ejemplo un aura encima de su cabeza, si kCCPositionTypeFree no.

• startSize: Tamaño de las partículas

• startSizeVar: Varianza de startSize

• endSize: Tamaño final de las partículas o kCCParticleStartSizeEqualToEndSize.

• EndSizeVar: Varianza de endSize.

• angle: ángulo de salida de las partículas.

• AngleVar: Varianza de angle.

• life: Tiempo de vida de cada partícula

• lifeVar:Varianza de life

• startColor: ccColor4F inicial

• startColorVar: varianza de startColor.

• EndColor: ccColor4F final.

• EndColorVar: varianza de endColor.

• blendFunc: ccBlendFunc struct. Bend de color de la textura (src) con el color de frame buffer (dest). Color = (x) src + (y) dst

• GL_ZERO ( 0, 0, 0, 0 )

• GL_ONE ( 1, 1, 1, 1 )

22

Page 23: SG Bienvenida Cocos2D

Slinger studios 2011

• GL_SRC_COLOR ( Rs / kR, Gs / kG, Bs / kB, As / kA )

• GL_ONE_MINUS_SRC_COLOR ( 1, 1, 1, 1 ) - ( Rs / kR, Gs / kG, Bs / kB, As / kA )

• GL_DST_COLOR ( Rd / kR, Gd / kG, Bd / kB, Ad / kA )

• GL_ONE_MINUS_DST_COLOR ( 1, 1, 1, 1 ) - ( Rd / kR, Gd / kG, Bd / kB, Ad / kA )

• GL_SRC_ALPHA ( As / kA, As / kA, As / kA, As / kA )

• GL_ONE_MINUS_SRC_ALPHA ( 1, 1, 1, 1 ) - ( As / kA, As / kA, As / kA, As / kA )

• GL_DST_ALPHA ( Ad / kA, Ad / kA, Ad / kA, Ad / kA )

• GL_ONE_MINUS_DST_ALPHA ( 1, 1, 1, 1 ) - ( Ad / kA, Ad / kA, Ad / kA, Ad / kA )

• GL_SRC_ALPHA_SATURATE ( i, i, i, 1 )

• blendAdditive: es equivalente a (GL_SRC_ALPHA, GL_ONE)

• texture: CCTexture desde [[CCTextureCache sharedTextureCache] .

Existen diversas formas de diseñar y crear efectos de partículas para cocos2d (por preferencia):

• ParticleDesigner: Aplicación comercial de bajo coste ( http://particledesigner.71squared.com.GUI para CCParticleSystem). Genera un plist. (Embed texture inserta la textura en el plist :( ).

system = [ARCH_OPTIMAL_PARTICLE_SYSTEM particleWithFile:@"fx1.plist"];

• Utilizando y personalizando algunos de los efectos preconstruidos en cocos2D. La lista incluye:

• CCParticleExplosion, CCParticleFire, CCParticleFireworks, CCParticleFlower, CCParticleGalaxy, CCParticleMeteor, CCParticleRain, CCParticleSmoke, CCParticleSnow, CCParticleSpiral, CCParticleSun

• Directamente heredando de las clase CCXXXParticleSystem.

#import <Foundation/Foundation.h>

#import "cocos2d.h"

// Depending on the targeted device the ParticleEffectSelfMade class will either derive

// from CCPointParticleSystem or CCQuadParticleSystem

@interface ParticleEffectSelfMade : ARCH_OPTIMAL_PARTICLE_SYSTEM

{

}

@end

23

Page 24: SG Bienvenida Cocos2D

Slinger studios 2011

SimpleAudioEngine.

• PlayBackgroundMusic:

[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"blues.mp3" loop:YES];

• playEffect:

[[SimpleAudioEngine sharedEngine] playEffect:@"alien-sfx.caf"];

CCCamera

El nodo cámara es usado por CCNode para establecer la vista a través de la función gluLookAt. Si el objeto es transformado (escalado, rotación, posicionamiento).

• Restore: devuelve a los valores por defecto.

• SetEyeX/ etEyeY/setCenterX/setCenterY: Establece los valores de la cámara.

CCLayerMultiplex

ES una layer que permite que permite multiplexar entre sus hijos (CCLayer).

• LayerWithLayers/initWithLayers: Inicialia el layer desde una array de hijos.

• SwitchTo/switchToAndReleaseMe: Cambia entre layer, si procede lo elimina de la lista.

Herramientas y macros importantes• CCLOG: wraps NSLOG con diversos niveles de control.• CCASSERT: wrap de macro defensive programming NSAssert.• CCARRAY: Cocos2D mutable array• CCRANDOM_0_1: Genera un numero aleatorio 0.0 … 1.0• CCARRAY_FOREACH: Iterador sobre las array de tipo CCArray.• CC_SWAP(x, y): Intercambia dos valores.• CCRANDOM_MINUS1_1: Random• CC_DEGREES_TO_RADIANS: Transforma grados en radianes• CC_RADIANS_TO_DEGREES: Transforma radianes en grados.• CC_ENABLE_DEFAULT_GL_STATES: habilita funcionalidades GL

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

•• CC_DISABLE_DEFAULT_GL_STATES: dehabilita funcionalidades GL• CC_DIRECTOR_INIT: Empaquetado del código de inicialización CCDirector• CC_DIRECTOR_END: Liberación del CCDIRECTOR

24

Page 25: SG Bienvenida Cocos2D

Slinger studios 2011

• CC_CONTENT_SCALE_FACTOR : Escala textura• Aritmética de puntos líneas y bounding boxes:

• CGRectContainsPoint: Comprueba que un punto este contenido o no en un boundingbox

• CGRectIntersectsRect: Mira la interseccion entre dos bounding boxes• CGRectIsEmpty: Comprueba que el bunding box esté inicializado.• En CGPointExtension.h

• CGFloat ccpLength(const CGPoint v)• CGFloat ccpDistance(const CGPoint v1, const CGPoint v2)• CGPoint ccpNormalize(const CGPoint v)• CGPoint ccpForAngle(const CGFloat a)• CGFloat ccpToAngle(const CGPoint v)• CGPoint ccpLerp(CGPoint a, CGPoint b, float alpha)• CGPoint ccpClamp(CGPoint p, CGPoint min_inclusive, CGPoint

max_inclusive)• CGPoint ccpFromSize(CGSize s)• CGPoint ccpCompOp(CGPoint p, float (*opFunc)(float))• BOOL ccpFuzzyEqual(CGPoint a, CGPoint b, float var)• CGPoint ccpCompMult(CGPoint a, CGPoint b)• float ccpAngleSigned(CGPoint a, CGPoint b)• CGPoint ccpRotateByAngle(CGPoint v, CGPoint pivot, float angle))• BOOL ccpLineIntersect(CGPoint p1, CGPoint p2,

CGPoint p3, CGPoint p4, float *s, float *t)

• NSStringFromSelector(_cmd): Retorna la decorated-name asociado al selector.• NSStringFromClass([xxx class])]: Retorna una cadena con el nombre de la clase.• Cocos2dVersion: Retorna la version de cocos2D.

Motores de físicas

Los motores de físicas más usados en cocos2d representas los diferentes sprites como objectos rígidos (por simplificación no se consideran masas deformables). Estos objetos físicos son de 2 tipos dinámicos y estáticos (ciertas optimizaciones se aplican bajo la hipótesis de que 2 objetos estáticos jamás colisionarán). Ambos tipos de objetos se modelan como formas (shapes) .Se pueden construir objetos complejos combinando objetos y uniendolos por articulaciones (joints) Cada colisión entre objetos crea unos puntos de contacto donde ambos objetos intersectan.

Los objetos presentas los siguientes atributos físicos que determina su comportamiento y posición:

• Densidad o masa: Cuanto pesa el objeto.

• Fricción: Cuanto cuesta moverlo, es decir la deceleración que aplican.

25

Page 26: SG Bienvenida Cocos2D

Slinger studios 2011

• Coeficiente de restitución: Cual elástico es el objeto.

Los objetos dinámicos se animan mediante la aplicación de:

• Fuerzas: Constantes en una dirección, por ejemplo para simular motores.

• Impulso: Fuerza que se aplica en un instante de tiempo. Por ejemplo para simular el lanzamiento de proyectiles.

• Torsiones: Fuerza que se aplica con un moviento angular.

Box2D

Box2D ( The Box2D API reference is distrib http://code.google.com/p/box2d.) está escrito en C++ y por tanto orientado a objetos, esto hace que el código que se integran sea más consistente con el resto de clases Objective-C. Box2D tiene funcionalidades adicionales a chipmunk como por ejemplo un mejor soporte para objetos que se mueven a grandes velocidades (por ejemplo balas), en chipmunk estos objetos presentan el problema del tunneling (objeto se mueva por encima de las velocidades que la física pueda exlicar y llegue a atravesar los objetos con los que colisiona).

Creación del objeto mundo

#import "cocos2d.h"

#import "Box2D.h"

#import "GLES-Render.h"

enum

{

kTagBatchNode,

};

@interface HelloWorld : CCLayer

{

b2World* world;

}

+(id) scene;

@end

Inicialización del objeto mundo

b2Vec2 gravity = b2Vec2(0.0f, -10.0f); // b2Vec2 gravity = vec1 + vec2; //soporta aritmetica de vectores.

bool allowBodiesToSleep = true; //Si sobre un objeto afecta fuerzas por debajo de un umbral se saca del pool de la interacción

world = new b2World(gravity, allowBodiesToSleep);

Acotando el mundo físico

// Define the static container body, which will provide the collisions at screen borders

26

Page 27: SG Bienvenida Cocos2D

Slinger studios 2011

b2BodyDef containerBodyDef;

b2Body* containerBody = world->CreateBody(&containerBodyDef);

// Create the screen box sides by using a polygon assigning each side individually

b2PolygonShape screenBoxShape;

int density = 0;

// For the ground body we'll need these values

//PTM_RATIO = Box2D optimized para distancias de 0.1 a 10 en metros!!! Se recomienda al menos 1 metro.

/// Esta constante determina que numero de pixels es 1 metro, por defecto 32.

CGSize screenSize = [CCDirector sharedDirector].winSize;

float widthInMeters = screenSize.width / PTM_RATIO;

float heightInMeters = screenSize.height / PTM_RATIO;

b2Vec2 lowerLeftCorner = b2Vec2(0, 0);

b2Vec2 lowerRightCorner = b2Vec2(widthInMeters, 0);

b2Vec2 upperLeftCorner = b2Vec2(0, heightInMeters);

b2Vec2 upperRightCorner = b2Vec2(widthInMeters, heightInMeters);

// Bottom

screenBoxShape.SetAsEdge(lowerLeftCorner, lowerRightCorner);

containerBody->CreateFixture(&screenBoxShape, density); //No utilizar setAsBox puesto que crea un objeto sólido!!!

// Top

screenBoxShape.SetAsEdge(upperLeftCorner, upperRightCorner);

containerBody->CreateFixture(&screenBoxShape, density);

// Left side

screenBoxShape.SetAsEdge(upperLeftCorner, lowerLeftCorner);

containerBody->CreateFixture(&screenBoxShape, density);

// Right side

screenBoxShape.SetAsEdge(upperRightCorner, lowerRightCorner);

containerBody->CreateFixture(&screenBoxShape, density);

Convertir puntos

//Por defecto Box2D trabaja en metros necesitamos varias funciones Helper para transformar valores.

-(b2Vec2) toMeters:(CGPoint)point

{

return b2Vec2(point.x / PTM_RATIO, point.y / PTM_RATIO);

}

-(CGPoint) toPixels:(b2Vec2)vec

{

27

Page 28: SG Bienvenida Cocos2D

Slinger studios 2011

return ccpMult(CGPointMake(vec.x, vec.y), PTM_RATIO);

}

CGPoint point = CGPointMake(100, 100);

b2Vec2 vec = b2Vec2(200, 200);

CGPoint pointFromVec;

pointFromVec = [self toPixels:vec];

b2Vec2 vecFromPoint;

vecFromPoint = [self toMeters:point];

Añadiendo Bodies al mundo

// Use the orthogonal tileset for the little boxes

CCSpriteBatchNode* batch = [CCSpriteBatchNode batchNodeWithFile:@"dg_grounds32.png" capacity:150];

[self addChild:batch z:0 tag:kTagBatchNode];

// Add a few objects initially

for (int i = 0; i < 11; i++)

{

[self addNewSpriteAt:CGPointMake(screenSize.width / 2, screenSize.height / 2)];

}

[self scheduleUpdate];

self.isTouchEnabled = YES;.

-(void) addNewSpriteAt:(CGPoint)pos

{

CCSpriteBatchNode* batch = (CCSpriteBatchNode*)[self getChildByTag:kTagBatchNode];

int idx = CCRANDOM_0_1() * TILESET_COLUMNS;

int idy = CCRANDOM_0_1() * TILESET_ROWS;

CGRect tileRect = CGRectMake(TILESIZE * idx, TILESIZE * idy, TILESIZE, TILESIZE);

CCSprite* sprite = [CCSprite spriteWithBatchNode:batch rect:tileRect];

sprite.position = pos;

[batch addChild:sprite];

/ / Create a body definition and set it to be a dynamic body

b2BodyDef bodyDef;

bodyDef.type = b2_dynamicBody;

bodyDef.position = [self toMeters:pos];

bodyDef.userData = sprite;

b2Body* body = world->CreateBody(&bodyDef);

// Define a box shape and assign it to the body fixture

28

Page 29: SG Bienvenida Cocos2D

Slinger studios 2011

b2PolygonShape dynamicBox;

f loat tileInMeters = TILESIZE / PTM_RATIO;

dynamicBox.SetAsBox(tileInMeters * 0.5f, tileInMeters * 0.5f);

b2FixtureDef fixtureDef;

fixtureDef.shape = &dynamicBox;

fixtureDef.density = 0.3f;

fixtureDef.friction = 0.5f;

fixtureDef.restitution = 0.6f;

body->CreateFixture(&fixtureDef);

}

Conectando objetos Box2D con sus sprites

-(void) update:(ccTime)delta

{

// Advance the physics world by one step, using fixed time steps

float timeStep = 0.03f;

int32 velocityIterations = 8;

int32 positionIterations = 1;

//Procesamos la fisica

//Primer argumento : el tiempo desde la anterior interaccion. Evitar pasar el delta puesto que el delta fluctua y destroza el rendimietno, mejor constante

//Segundo argumento numero de intaracciones para calcular el movimiento de los objetos. Es la precision que deseamos. Más de 10 no es discernible n videojuegos.

//Tercer argumento. Es el número de pasadas por interacción. No es normal necesitar más refinamiento que 1 pasada.

world->Step(timeStep, velocityIterations, positionIterations);

for (b2Body* body = world->GetBodyList(); body != nil; body = body->GetNext())

{

CCSprite* sprite = (CCSprite*)body->GetUserData();

if (sprite!= NULL)

{

sprite.position = [self toPixels:body->GetPosition()];

f loat angle = body->GetAngle();

sprite.rotation = CC_RADIANS_TO_DEGREES(angle) * -1;

}

}

}

29

Page 30: SG Bienvenida Cocos2D

Slinger studios 2011

Detección de la colision

//Se produce por callback para ello es preciso crear una clase C++ (extension .mm) y decirle a xcode que la trate como tal.

#import "Box2D.h"

class ContactListener : public b2ContactListener

{

private:

void BeginContact(b2Contact* contact);

void EndContact(b2Contact* contact);

};

#import "ContactListener.h"

#import "cocos2d.h"

void ContactListener::BeginContact(b2Contact* contact)

{

b2Body* bodyA = contact->GetFixtureA()->GetBody();

b2Body* bodyB = contact->GetFixtureB()->GetBody();

CCSprite* spriteA = (CCSprite*)bodyA->GetUserData();

CCSprite* spriteB = (CCSprite*)bodyB->GetUserData();

if (spriteA != NULL && spriteB != NULL)

{

spriteA.color = ccMAGENTA;

spriteB.color = ccMAGENTA;

}

}

void ContactListener::EndContact(b2Contact* contact)

{

b2Body* bodyA = contact->GetFixtureA()->GetBody();

b2Body* bodyB = contact->GetFixtureB()->GetBody();

CCSprite* spriteA = (CCSprite*)bodyA->GetUserData();

CCSprite* spriteB = (CCSprite*)bodyB->GetUserData();

if (spriteA != NULL && spriteB != NULL)

{

spriteA.color = ccWHITE;

spriteB.color = ccWHITE;

}

}

30

Page 31: SG Bienvenida Cocos2D

Slinger studios 2011

#import "cocos2d.h"

#import "Box2D.h"

#import "GLES-Render.h"

#import "ContactListener.h"

...

@interface HelloWorld : CCLayer

{

b2World* world;

//Añadiemos clase del callback

ContactListener* contactListener;

}

contactListener = new ContactListener();

//registramos callback

world->SetContactListener(contactListener);

-(void) dealloc

{

delete contactListener;

delete world;

[super dealloc];

}

Definiendo objetos complejos (Joints)

-(void) addSomeJoinedBodies:(CGPoint)pos

{

// Create a body definition and set it to be a dynamic body

b2BodyDef bodyDef;

bodyDef.type = b2_dynamicBody;

// Position must be converted to meters

bodyDef.position = [self toMeters:pos];

bodyDef.position = bodyDef.position + b2Vec2(-1, -1);

bodyDef.userData = [self addRandomSpriteAt:pos];

b2Body* bodyA = world->CreateBody(&bodyDef);

[self bodyCreateFixture:bodyA];

bodyDef.position = [self toMeters:pos];

bodyDef.userData = [self addRandomSpriteAt:pos];

31

Page 32: SG Bienvenida Cocos2D

Slinger studios 2011

b2Body* bodyB = world->CreateBody(&bodyDef);

[self bodyCreateFixture:bodyB];

bodyDef.position = [self toMeters:pos];

bodyDef.position = bodyDef.position + b2Vec2(1, 1);

bodyDef.userData = [self addRandomSpriteAt:pos];

b2Body* bodyC = world->CreateBody(&bodyDef);

[self bodyCreateFixture:bodyC];

// Create the revolute joints, allow 360º rotation

b2RevoluteJointDef jointDef;

jointDef.Initialize(bodyA, bodyB, bodyB->GetWorldCenter());

bodyA->GetWorld()->CreateJoint(&jointDef);

jointDef.Initialize(bodyB, bodyC, bodyC->GetWorldCenter());

bodyA->GetWorld()->CreateJoint(&jointDef);

// Create an invisible static body and attach body A to it

bodyDef.type = b2_staticBody;

bodyDef.position = [self toMeters:pos];

b2Body* staticBody = world->CreateBody(&bodyDef);

jointDef.Initialize(staticBody, bodyA, bodyA->GetWorldCenter());

bodyA->GetWorld()->CreateJoint(&jointDef);

}

Box2D Debug Drawing

//This is where the GLESDebugDraw class comes in handy.

-(void) enableBox2dDebugDrawing

{

debugDraw = new GLESDebugDraw(PTM_RATIO);

world->SetDebugDraw(debugDraw);

uint32 flags = b2DebugDraw::e_shapeBit;

debugDraw->SetFlags(flags);

}

//En una clase

#ifdef DEBUG

-(void) draw

{

glDisable(GL_TEXTURE_2D);

glDisableClientState(GL_COLOR_ARRAY);

32

Page 33: SG Bienvenida Cocos2D

Slinger studios 2011

glDisableClientState(GL_TEXTURE_COORD_ARRAY);

world->DrawDebugData();

// restore default GL states

glEnable(GL_TEXTURE_2D);

glEnableClientState(GL_COLOR_ARRAY);

glEnableClientState(GL_TEXTURE_COORD_ARRAY);

}

#endif

Aplicando fuerzas

-(void) applyForceTowardsFinger

{

b2Vec2 bodyPos = body->GetWorldCenter();

b2Vec2 fingerPos = [Helper toMeters:fingerLocation];

b2Vec2 bodyToFinger = fingerPos - bodyPos;

bodyToFinger.Normalize();

b2Vec2 force = 2.0f * bodyToFinger;

body->ApplyForce(force, body->GetWorldCenter());

}

ChipMunk

Escrito en C mediante el uso de estructuras para representar los objetos. Chipmunk space manager es una interface para objectice-C que permite vincular sprites con objetos chipmunk para actualizar su posición de forma más sencilla.

Inicilizar chipmunk

cpInitChipmunk();

space = cpSpaceNew();

space->iterations = 8; //Valor minimo para obtener bueno rendimientos.

space->gravity = CGPointMake(0, -100);

-(void) dealloc

{

cpSpaceFree(space);

[super dealloc];

}

33

Page 34: SG Bienvenida Cocos2D

Slinger studios 2011

Acotando el mundo físico

// For the ground body we'll need these values

CGSize screenSize = [CCDirector sharedDirector].winSize;

CGPoint lowerLeftCorner = CGPointMake(0, 0);

CGPoint lowerRightCorner = CGPointMake(screenSize.width, 0);

CGPoint upperLeftCorner = CGPointMake(0, screenSize.height);

CGPoint upperRightCorner = CGPointMake(screenSize.width, screenSize.height);

// Create the static body that keeps objects within the screen. Set mass=inertia=INFINITY

float mass = INFINITY;

float inertia = INFINITY;

cpBody* staticBody = cpBodyNew(mass, inertia);

cpShape* shape;

float elasticity = 1.0f;

float friction = 1.0f;

float radius = 0.0f;

// Bottom

shape = cpSegmentShapeNew(staticBody, lowerLeftCorner, lowerRightCorner, radius);

shape->e = elasticity;

shape->u = friction;

cpSpaceAddStaticShape(space, shape);

// Top

shape = cpSegmentShapeNew(staticBody, upperLeftCorner, upperRightCorner, radius);

shape->e = elasticity;

shape->u = friction;

cpSpaceAddStaticShape(space, shape);

// Left side

shape = cpSegmentShapeNew(staticBody, lowerLeftCorner, upperLeftCorner, radius);

shape->e = elasticity;

shape->u = friction;

cpSpaceAddStaticShape(space, shape);

// Right side

shape = cpSegmentShapeNew(staticBody, lowerRightCorner, upperRightCorner, radius);

shape->e = elasticity;

34

Page 35: SG Bienvenida Cocos2D

Slinger studios 2011

shape->u = friction;

cpSpaceAddStaticShape(space, shape);

Añadiendo Bodies al mundo

-(void) addNewSpriteAt:(CGPoint)pos

{

float mass = 0.5f;

float moment = cpMomentForBox(mass, TILESIZE, TILESIZE);

cpBody* body = cpBodyNew(mass, moment);

body->p = pos;

cpSpaceAddBody(space, body);

float halfTileSize = TILESIZE * 0.5f;

int numVertices = 4;

CGPoint vertices[] =

{

CGPointMake(-halfTileSize, -halfTileSize),

CGPointMake(-halfTileSize, halfTileSize),

CGPointMake(halfTileSize, halfTileSize),

CGPointMake(halfTileSize, -halfTileSize),

};

CGPoint offset = CGPointZero;

float elasticity = 0.3f;

float friction = 0.7f;

cpShape* shape = cpPolyShapeNew(body, numVertices, vertices, offset);

shape->e = elasticity;

shape->u = friction;

shape->data = [self addRandomSpriteAt:pos];

cpSpaceAddShape(space, shape);

}

Conectando objetos chipmunk con sus sprites

-(void) update:(ccTime)delta

{

float timeStep = 0.03f;

cpSpaceStep(space, timeStep);

35

Page 36: SG Bienvenida Cocos2D

Slinger studios 2011

// Call forEachShape C method to update sprite positions

cpSpaceHashEach(space->activeShapes, &forEachShape, nil);

cpSpaceHashEach(space->staticShapes, &forEachShape, nil);

}

// C method that updates sprite position and rotation:

static void forEachShape(void* shapePointer, void* data)

{

cpShape* shape = (cpShape*)shapePointer;

CCSprite* sprite = (CCSprite*)shape->data;

if (sprite != nil)

{

cpBody* body = shape->body;

sprite.position = body->p;

sprite.rotation = CC_RADIANS_TO_DEGREES(body->a) * -1;

}

}

Detección de la colision

static int contactBegin(cpArbiter* arbiter, struct cpSpace* space, void* data)

{

bool processCollision = YES;

cpShape* shapeA;

cpShape* shapeB;

cpArbiterGetShapes(arbiter, &shapeA, &shapeB);

CCSprite* spriteA = (CCSprite*)shapeA->data;

CCSprite* spriteB = (CCSprite*)shapeB->data;

if (spriteA != nil && spriteB != nil)

{

spriteA.color = ccMAGENTA;

spriteB.color = ccMAGENTA;

}

return processCollision; //Si se retorna NO se ignora las colisiones

}

36

Page 37: SG Bienvenida Cocos2D

Slinger studios 2011

static void contactEnd(cpArbiter* arbiter, cpSpace* space, void* data)

{

cpShape* shapeA;

cpShape* shapeB;

cpArbiterGetShapes(arbiter, &shapeA, &shapeB);

CCSprite* spriteA = (CCSprite*)shapeA->data;

CCSprite* spriteB = (CCSprite*)shapeB->data;

if (spriteA != nil && spriteB != nil)

{

spriteA.color = ccWHITE;

spriteB.color = ccWHITE;

}

}

….

unsigned int defaultCollisionType = 0;

//Registramos el callback

//space: espacio mundo

//defaultCollision: ignorar el parametro collision_type de los shapes. Si es distinto de cero permite filtrar por este valor.

// contactBegin: begin

// contactPreSolve: pre-solve code

// contactPreSolve: post solve code

//contactEnd: separation code

//data: void* libre

cpSpaceAddCollisionHandler(space, defaultCollisionType, defaultCollisionType,&contactBegin, /*contactPreSolve */NULL, /*contactPreSolve */NULL,&contactEnd, /*data*/NULL);

Definiendo objetos complejos (Joints)

-(void) addSomeJoinedBodies:(CGPoint)pos

{

float mass = 1.0f;

float moment = cpMomentForBox(mass, TILESIZE, TILESIZE);

float halfTileSize = TILESIZE * 0.5f;

int numVertices = 4;

CGPoint vertices[] =

37

Page 38: SG Bienvenida Cocos2D

Slinger studios 2011

{

CGPointMake(-halfTileSize, -halfTileSize),

CGPointMake(-halfTileSize, halfTileSize),

CGPointMake(halfTileSize, halfTileSize),

CGPointMake(halfTileSize, -halfTileSize),

};

// Create a static body

cpBody* staticBody = cpBodyNew(INFINITY, INFINITY);

staticBody->p = pos;

CGPoint offset = CGPointZero;

cpShape* shape = cpPolyShapeNew(staticBody, numVertices, vertices, offset);

cpSpaceAddStaticShape(space, shape);

// Create three new dynamic bodies

float posOffset = 1.4f;

pos.x += TILESIZE * posOffset;

cpBody* bodyA = cpBodyNew(mass, moment);

bodyA->p = pos;

cpSpaceAddBody(space, bodyA);

shape = cpPolyShapeNew(bodyA, numVertices, vertices, offset);

shape->data = [self addRandomSpriteAt:pos];

cpSpaceAddShape(space, shape);

pos.x += TILESIZE * posOffset;

cpBody* bodyB = cpBodyNew(mass, moment);

bodyB->p = pos;

cpSpaceAddBody(space, bodyB);

shape = cpPolyShapeNew(bodyB, numVertices, vertices, offset);

shape->data = [self addRandomSpriteAt:pos];

cpSpaceAddShape(space, shape);

pos.x += TILESIZE * posOffset;

cpBody* bodyC = cpBodyNew(mass, moment);

bodyC->p = pos;

cpSpaceAddBody(space, bodyC);

shape = cpPolyShapeNew(bodyC, numVertices, vertices, offset);

shape->data = [self addRandomSpriteAt:pos];

38

Page 39: SG Bienvenida Cocos2D

Slinger studios 2011

cpSpaceAddShape(space, shape);

// Create the

cpConstraint* constraint1 = cpPivotJointNew(staticBody, bodyA, staticBody->p);

cpConstraint* constraint2 = cpPivotJointNew(bodyA, bodyB, bodyA->p);

cpConstraint* constraint3 = cpPivotJointNew(bodyB, bodyC, bodyB->p);

cpSpaceAddConstraint(space, constraint1);

cpSpaceAddConstraint(space, constraint2);

cpSpaceAddConstraint(space, constraint3);

}

Listado de acciones

Posicion

Modifica el atributo position del nodo.

• CCMoveBy: Movimiento relativo del nodo dado un incremento.

• CCMoveTo:Moviemiento absoluto del nodo a una posicion dada.

• CCJumpBy: Movimiento simulando un salto parabolico en coordenadas relativas.

• CCJumpTo: Movimiento simulando un salto parabolico en coordenadas absolutas

• CCBezierBy: Movimiento siguiendo una curva de Bezier en coordenadas relativas.

• CCBezierTo:Movimiento siguiendo una curva de Bezier en coordenadas absolutas.

• CCPlace:

Escalado

Modifica el atributo scale del nodo.

• CCScaleBy: Escalado del nodo por incremento relativo.

• CCScaleTo: Escalado del nodo en incremento absoluto.

Rotaciones

Modifica el atributo rotation del nodo.

• CCRotateBy: Rota el nodo en grados de forma relativa.

• CCRotateTo:Rota el nodo en grados de forma absoluta.

39

Page 40: SG Bienvenida Cocos2D

Slinger studios 2011

Visibilidad

Modifica el atributo visible del nodo.

• CCShow: Muestra el nodo

• CCHide: Oculta el nodo.

• CCBlink: Hace parpadear el nodo.

• CCToggleVisibility:cambia el estado de visible

Opacidad

Modifica los valores del canal alpha del nodo.

• CCFadeIn: Realiza el efecto de hacer aparecer el nodo

• CCFadeOut:: Realiza el efecto de hacer desaparecer el nodo

• CCFadeTo: modifica el valor del canal alpha del nodo.

Color

Modifica los valores de color del nodo.

• CCTintBy: Modificación del color en valores relativos.

• CCTintTo:Modificación del color en valores absolutos.

Grid/TileGrid

Permite realizar modificacion del mesh sencillas. El nodo del estructura según el siguiente mapa

• CCFlipX3D:

40

Page 41: SG Bienvenida Cocos2D

Slinger studios 2011

• CCFlipY3D:

• CCLens3D:

• CCLiquid:

• CCRipple3D:

• CCShaky3D:

• CCTwirl:

• CCWaves:

• CCWaves3D:

• CCFadeOutBLTile:

• CCFadeOutTRTiles:

• CCFadeOutUpTiles:

• CCFadeOutDownTiles:

• CCJumpTiles3D:

• CCShakyTiles3D:

• CCShatteredTiles3D:

• CCShuffleTiles:

• CCSplitCols:

• CCSplitRows:

• CCTurnOffTiles:

• CCWavesTiles3D:

Composicion:

Permite agrupa varias accciones en una unica primitiva.

• CCSequence:Ejecuta una secuencia de acciones.

• CCSpawn:Ejecuta varias acciones al mismo tiempo.

• CCRepeat:Ejecuta varias acciones un bucle finito.

• CCRepeatForever:Ejecuta varias acciones en un bucle infinito.

Ease

La ejecución de las acciones se produce según una curva dada.

41

Page 42: SG Bienvenida Cocos2D

Slinger studios 2011

• CCEaseIn: Pendiente positiva

• CCEaseOut: Pediente negativa

• CCEaseInOut: Triangular.

• CCEaseExponentialIn:

• CCEaseExponentialOut:

• CCEaseExponentialInOut:

• CCEaseSineIn:

• CCEaseSineOut:

• CCEaseSineInOut:

42

Page 43: SG Bienvenida Cocos2D

Slinger studios 2011

• CCEaseElasticIn:

• CCEaseElasticOut:

• CCEaseElasticInOut:

• CCEaseBounceIn:

• CCEaseBounceOut:

• CCEaseBounceInOut:

• CCEaseBackIn:

• CCEaseBackOut:

• CCEaseBackInOut:

43

Page 44: SG Bienvenida Cocos2D

Slinger studios 2011

• CCSpeed: Incrementa la velocidad de la acción en curso.

Otras

• CCPropertyAction: Modifca el valor de un propiedad

• CCFollow: Situa la camara asociada a un nodo.

• CCCallFunc/CCCallFuncN/CCCallFuncND: Permite ejecutar métodos propios

• CCCallBlock/CallBlockN: Permite ejecutar métodos propios en forma de bloques.

• CCAnimation: Realiza una animación sobr el nodo.

Listado de transiciones de escena

Fade

• CCTransitionFade:Hace desaparecer la escena en curso y aparece la nueva

• Fade tiles

• CCFadeTRTransition: Fade tiles hacia arriba+derecha

• CCFadeBLTransition: Fade tiles hacia abajo+izquieda

• CCFadeDownTransition: Fade tiles hacia abajo

• CCFadeUpTransition:Fade tiles hacia arriba.

Movimiento

• CCMoveInBTransition: Movimiento hacia abajo.

• CCMoveInRTransition: Movimiento hacia la derecha.

• CCMoveInTTransition: Movimiento hacia arriba.

• CCMoveInLTransition: Movimiento hacia izquierda.

Solapamientos

• CCOrientedTransitionScene: Solapamiento en las 4 direcciones.

• CCFlipAngularTransition:Flip ½ de forma horizontal y vertical.

• CCFlipXTransition: Flip horizontal

• CCFlipYTransition: Flip vertical

• CCZoomFlipAngularTransition::Flip ½ de forma horizontal y vertical.cpn zoom.

44

Page 45: SG Bienvenida Cocos2D

Slinger studios 2011

• CCZoomFlipXTransition:Flip horizontal con zoom

• CCZoomFlipYTransition:Flip vertical con zoom

Diapositivas

• CCSlideInLTransition: Diapositivas hacia la izquierda

• CCSlideInRTransition: Diapositivas hacia la derecha

• CCSlideInTTransition: Diapositivas hacia la arriba

• CCSlideInBTransition: Diapositivas hacia la abajo

Interlineado

• CCSplitColsTransition: Interlineado por columnas

• CCSplitRowsTransition: Interlineado por filas

Otros

• CCJumpZoomTransition: Hace zoom y emula salto parabólico, idem con la entrante.

• CCPageTurnTransition: Simular el girar página

• CCRotoZoomTransition: Hace zoom y rota las escenas

• CCShrinkGrowTransition: El entrante escala de menos a mas y la saliente a la inversa

• CCTurnOffTilesTransition: Reemplaza tiles de forma aleatoria.

Tips, tricks and code snippets

Comproba el tipo de un CCNode

CCNode* node = [self getChildByTag:UILayerTagFrameSprite];NSAssert([node isKindOfClass:[CCSprite class]], @"node is not aCCSprite");

.

¿Niveles como CCScene o como CCLayer?

Niveles como escenas. Cuando se tengan niveles claramente separados y lo que ocurren en el nivel no tiene relevancia para los siguientes, es decir no se debe guardar los estados de cada nivel.Niveles como layers. Escenas mśa complejas donde cada nivel no deba ser reseteado en la entrada. La clase CCMultiplexLayer es la ideal para ello.CCLayer* layer1 = [CCLayer node];CCLayer* layer2 = [CCLayer node];

45

Page 46: SG Bienvenida Cocos2D

Slinger studios 2011

CCMultiplexLayer* mpLayer = [CCMultiplexLayer layerWithLayers:layer1, layer2, nil];// Switches to layer2 but keeps layer1 as child of mpLayer.[mpLayer switchTo:1];// Switches to layer1, removes layer2 from mpLayer and releases its memory.// After this call you must not switch back to layer2 (index: 1) anymore![mpLayer switchToAndReleaseMe:0];

¿Heredar objetos del juego por herencia o por composición?

El primer problema al que nos enfretamos es decidir de que clase se debe heredar. Heredar de CCSprite no es buena idea puesto que obliga a que cada componente del juego que deba tener su clase tiene una representación grafica y una textura. ¿Que pasa si simplemente queremos representar mensaje de texto?. La mejor elección es heredar de CCNode.

Para aquellos caso en los que si debe existir una representación gráfica por texturas es mejor utilizar la composición para representar la relación 'has-a” = tiene una representación gráfica que es esta.

Crear animaciones

Usamos las clases CCAnimation y la acciónCCAnimate.El proceso se resume en

• Crear una instancia NSMutableArray para guardar las imágenes

• Para cada frame de la animación

• Crear una CCTexture2D para cada imagen

• Crear el CCSpriteFrame usando la clase CCTexture2D

• Añadir a la NSMutableArray

• Crear una clase CCAnimation para guardar la secuencia

• Opcionalmente añadir esta clase al nodo CCSprite

• Usar una acción CCAnimate para ejecutar la animación.

// Load the ship's animation frames as textures and create a sprite frameNSMutableArray* frames = [NSMutableArray arrayWithCapacity:5];for (int i = 0; i < 5; i++){ // Create a texture for the animation frame NSString* file = [NSString stringWithFormat:@"ship-anim%i.png", i]; CCTexture2D* texture = [[CCTextureCache sharedTextureCache] addImage:file]; // The whole image should be used as the animation frame CGSize texSize = [texture contentSize]; CGRect texRect = CGRectMake(0, 0, texSize.width, texSize.height);

46

Page 47: SG Bienvenida Cocos2D

Slinger studios 2011

// Create a sprite frame from the texture CCSpriteFrame* frame = [CCSpriteFrame frameWithTexture:texture rect:texRect offset:CGPointZero]; [frames addObject:frame];}

// Create an animation object from all the sprite animation framesCCAnimation* anim = [CCAnimation animationWithName:@"move" delay:0.08f frames:frames];// Run the animation by using the CCAnimate action and loop it with CCRepeatForeverCCAnimate* animate = [CCAnimate actionWithAnimation:anim];CCRepeatForever* repeat = [CCRepeatForever actionWithAction:animate];[self runAction:repeat];

CCAnimation* anim = [CCAnimation animationWithName:@"move" delay:1 frames:frames];// Store the animation in the CCSprite node[mySprite addAnimation:anim];// Sometime later: retrieve the move animation from the CCSprite nodeCCAnimation* moveAnim = [mySprite animationByName:@”move”];

Animation Helper

Usamos la funcionalidad de objetctive C para crear extensiónes sobre las clases (categorias).

@interface CCAnimation (Helper)

+(CCAnimation*) animationWithFile:(NSString*)name frameCount:(int)frameCount delay:(float)delay;

@end

@implementation CCAnimation (Helper)

// Creates an animation from single files

+(CCAnimation*) animationWithFile:(NSString*)name frameCount:(int)frameCount delay:(float)delay

{

// Load the animation frames as textures and create the sprite frames

NSMutableArray* frames = [NSMutableArray arrayWithCapacity:frameCount];

for (int i = 0; i < frameCount; i++)

{

// Assuming all animation files are named "nameX.png"

NSString* file = [NSString stringWithFormat:@"%@%i.png", name, i];

CCTexture2D* texture = [[CCTextureCache sharedTextureCache] addImage:file];

// Assuming that image file animations always use the whole image

CGSize texSize = texture.contentSize;

CGRect texRect = CGRectMake(0, 0, texSize.width, texSize.height);

47

Page 48: SG Bienvenida Cocos2D

Slinger studios 2011

CCSpriteFrame* frame = [CCSpriteFrame frameWithTexture:texture rect:texRect offset:CGPointZero];

[frames addObject:frame];

}

// Return an animation object from all the sprite animation frames

return [CCAnimation animationWithName:name delay:delay frames:frames];

}

Usando Texture Atlas

Para usar texture atlas cocos necesita tanto el fichero .png como el .plist. La magia reside en :

• Usar una clase CCSpriteFrameCache para cargar la definición

• El método de la clase spriteFrameCache para generar el CCSpriteFrame correspondiente.

// Load the Texture Atlas sprite frames; this also loads the Texture with the same nameCCSpriteFrameCache* frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];

[frameCache addSpriteFramesWithFile:@"ship-and-bullet.plist"];

// Loading the ship's sprite using a sprite frame name (e.g., the file name) if ((self = [super initWithSpriteFrameName:@"ship.png"])) { // Load the ship's animation frames NSMutableArray* frames = [NSMutableArray arrayWithCapacity:5]; for (int i = 0; i < 5; i++) { NSString* file = [NSString stringWithFormat:@"ship-anim%i.png", i]; CCSpriteFrame* frame = [frameCache spriteFrameByName:file];

[frames addObject:frame]; } // Create an animation object from all the sprite animation frames CCAnimation* anim = [CCAnimation animationWithName:@"move" delay:0.08f frames:frames]; // Run the animation by using the CCAnimate action CCAnimate* animate = [CCAnimate actionWithAnimation:anim]; CCRepeatForever* repeat = [CCRepeatForever actionWithAction:animate]; [self runAction:repeat]; }

¿Como hacer un parallax infitnito?

El objetivo es evitar las zonas sin textura a medida que las capas del parallax se desplazan. El truco es trabajar con dos sprites identicos y colocarno uno al lado del otro en horizontal, cuando se detecta que uno que totalmente fuera de la vista lo recolocamos.

48

Page 49: SG Bienvenida Cocos2D

Slinger studios 2011

-(void) update:(ccTime)delta{ CCSprite* sprite; CCARRAY_FOREACH([spriteBatch children], sprite) { NSNumber* factor = [speedFactors objectAtIndex:sprite.zOrder]; CGPoint pos = sprite.position; pos.x -= scrollSpeed * [factor floatValue]; // Reposition stripes when they're out of bounds if (pos.x < -screenSize.width) { pos.x += screenSize.width * 2; } sprite.position = pos; }}

Otra opcion es definir el área del sprite de fondo con grandes dimensiones y utilizar el parametro GL GL_REPEAT.

CGRect repeatRect = CGRectMake(-5000, -5000, 5000, 5000);CCSprite* sprite = [CCSprite spriteWithFile:@”square.png” rect:repeatRect];ccTexParams params ={ GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT};[sprite.texture setTexParameters:&params];

Cambiar la textura asociada a un CCSprite

MySprite = [CCSprite spriteWithSpriteFrameName:@"SomeName.png"];

//[MySprite setTextureRect:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: @"SomeOtherName.png" ].rect ]; //deprecated[MySprite setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: @"SomeOtherName.png"]];

¿Crear game object por herencia o por composición?

• Por herencia: Si los objetos son simples y nos se producen muchas variaciones de comportamiento en las clases derivadas puede resultar util. Si no es el caso puede enmascarar un antipatron de comportamiento condicionado con abuso de clausulas IF y duplicidad de código.

49

Page 50: SG Bienvenida Cocos2D

Slinger studios 2011

• Por composición: Se ha desmostrado ser un patrón más flexible y escalable. Esto implica crear familias de componentes de cada uno de los aspectos que constituyen un game object:

• Representación gráfica

• Posición

• Objeto/Shape fisica

• Sonidos y música

• Comportamientos (IA)

• Salud (health)

• Inventario

• OTROS....

Creacion de un XXXSpriteCache para optimizar rendimiento

La idea ehs crear una cache con un atributo CCSpriteBatchNode en aquellos casos en los cuales tengamos un número máximo de objetos de algún tipo (enemigos, balas,...). Derivar estos CCSprites para añadir atributos que nos permitan controlarlos y reutilizarlos de manera sencillas (posicion, usado, visible,...).

¿Como utilizar el Game center de Apple?

Game center permite guardar información de los jugadores, sus logros y premios, puntuación y leaderboards. Los pasos a seguir son los siguientes:

• Registrar nuestra aplicación en iTunes connect (https://itunesconnect.apple.com. O https://itunesconnect.apple.com/docs/iTunesConnect_DeveloperGuide.pdf.). Especificando el Bundle ID de nuestra aplicación.

• Habilitar game center para nuestro juego (a game that uses Game Center is at Apple’s Getting Started http://developer.apple.com/devcenter/ios/gamecenter.).

• Creamos las leaderboards y logros de nuestra aplicación.

• Opcional. Marcamos la presencia de game center como un requisito creando una nueva clave gameckit a YES en el bloque UIRequiredDeviceCapabilitiesBoolean del fichero plist de la aplicación.

• Añadir GameKit.framework a las dependencias del proyecto. Por defecto es añade las librerias como required , en caso de no quere que sea un requisito cambiar al valor weak.

• Añadir GameKit.h en el fichero de librerias precompiladas Prefix.pch.

50

Page 51: SG Bienvenida Cocos2D

Slinger studios 2011

• Crear una clase helper para suscribirse a los eventos y notificaciones del game center.

//// GameKitHelper.h//// Created by Steffen Itterheim on 05.10.10.// Copyright 2010 Steffen Itterheim. All rights reserved.//

#import "cocos2d.h"#import <GameKit/GameKit.h>

@protocol GameKitHelperProtocol

-(void) onLocalPlayerAuthenticationChanged;

-(void) onFriendListReceived:(NSArray*)friends;-(void) onPlayerInfoReceived:(NSArray*)players;

-(void) onScoresSubmitted:(bool)success;-(void) onScoresReceived:(NSArray*)scores;

-(void) onAchievementReported:(GKAchievement*)achievement;-(void) onAchievementsLoaded:(NSDictionary*)achievements;-(void) onResetAchievements:(bool)success;

-(void) onMatchFound:(GKMatch*)match;-(void) onPlayersAddedToMatch:(bool)success;-(void) onReceivedMatchmakingActivity:(NSInteger)activity;

-(void) onPlayerConnected:(NSString*)playerID;-(void) onPlayerDisconnected:(NSString*)playerID;-(void) onStartMatch;-(void) onReceivedData:(NSData*)data fromPlayer:(NSString*)playerID;

-(void) onMatchmakingViewDismissed;-(void) onMatchmakingViewError;-(void) onLeaderboardViewDismissed;-(void) onAchievementsViewDismissed;

@end

@interface GameKitHelper : NSObject <GKLeaderboardViewControllerDelegate, GKAchievementViewControllerDelegate, GKMatchmakerViewControllerDelegate, GKMatchDelegate>{

id<GameKitHelperProtocol> delegate;bool isGameCenterAvailable;NSError* lastError;

NSMutableDictionary* achievements;NSMutableDictionary* cachedAchievements;

51

Page 52: SG Bienvenida Cocos2D

Slinger studios 2011

GKMatch* currentMatch;bool matchStarted;

}

@property (nonatomic, retain) id<GameKitHelperProtocol> delegate;@property (nonatomic, readonly) bool isGameCenterAvailable;@property (nonatomic, readonly) NSError* lastError;@property (nonatomic, readonly) NSMutableDictionary* achievements;@property (nonatomic, readonly) GKMatch* currentMatch;@property (nonatomic, readonly) bool matchStarted;

/** returns the singleton object, like this: [GameKitHelper sharedGameKitHelper] */+(GameKitHelper*) sharedGameKitHelper;

// Player authentication, info-(void) authenticateLocalPlayer;-(void) getLocalPlayerFriends;-(void) getPlayerInfo:(NSArray*)players;

// Scores-(void) submitScore:(int64_t)score category:(NSString*)category;

-(void) retrieveScoresForPlayers:(NSArray*)playerscategory:(NSString*)category range:(NSRange)range

playerScope:(GKLeaderboardPlayerScope)playerScope timeScope:(GKLeaderboardTimeScope)timeScope;

-(void) retrieveTopTenAllTimeGlobalScores;

// Achievements-(GKAchievement*) getAchievementByID:(NSString*)identifier;-(void) reportAchievementWithID:(NSString*)identifier percentComplete:(float)percent;-(void) resetAchievements;-(void) reportCachedAchievements;-(void) saveCachedAchievements;

// Matchmaking-(void) disconnectCurrentMatch;-(void) findMatchForRequest:(GKMatchRequest*)request;-(void) addPlayersToMatch:(GKMatchRequest*)request;-(void) cancelMatchmakingRequest;-(void) queryMatchmakingActivity;

// Game Center Views-(void) showLeaderboard;-(void) showAchievements;-(void) showMatchmakerWithInvite:(GKInvite*)invite;-(void) showMatchmakerWithRequest:(GKMatchRequest*)request;

@end

//// GameKitHelper.m

52

Page 53: SG Bienvenida Cocos2D

Slinger studios 2011

//// Created by Steffen Itterheim on 05.10.10.// Copyright 2010 Steffen Itterheim. All rights reserved.//

#import "GameKitHelper.h"

static NSString* kCachedAchievementsFile = @"CachedAchievements.archive";

@interface GameKitHelper (Private)-(void) registerForLocalPlayerAuthChange;-(void) setLastError:(NSError*)error;-(void) initCachedAchievements;-(void) cacheAchievement:(GKAchievement*)achievement;-(void) uncacheAchievement:(GKAchievement*)achievement;-(void) loadAchievements;-(void) initMatchInvitationHandler;-(UIViewController*) getRootViewController;@end

@implementation GameKitHelper

static GameKitHelper *instanceOfGameKitHelper;

#pragma mark Singleton stuff+(id) alloc{

@synchronized(self){

NSAssert(instanceOfGameKitHelper == nil, @"Attempted to allocate a second instance of the singleton: GameKitHelper");

instanceOfGameKitHelper = [[super alloc] retain];return instanceOfGameKitHelper;

}

// to avoid compiler warningreturn nil;

}

+(GameKitHelper*) sharedGameKitHelper{

@synchronized(self){

if (instanceOfGameKitHelper == nil){

[[GameKitHelper alloc] init];}

return instanceOfGameKitHelper;}

// to avoid compiler warningreturn nil;

53

Page 54: SG Bienvenida Cocos2D

Slinger studios 2011

}

#pragma mark Init & Dealloc

@synthesize delegate;@synthesize isGameCenterAvailable;@synthesize lastError;@synthesize achievements;@synthesize currentMatch;@synthesize matchStarted;

-(id) init{

if ((self = [super init])){

// Test for Game Center availabilityClass gameKitLocalPlayerClass = NSClassFromString(@"GKLocalPlayer");bool isLocalPlayerAvailable = (gameKitLocalPlayerClass != nil);

// Test if device is running iOS 4.1 or higherNSString* reqSysVer = @"4.1";NSString* currSysVer = [[UIDevice currentDevice] systemVersion];bool isOSVer41 = ([currSysVer compare:reqSysVer options:NSNumericSearch] !=

NSOrderedAscending);

isGameCenterAvailable = (isLocalPlayerAvailable && isOSVer41);NSLog(@"GameCenter available = %@", isGameCenterAvailable ? @"YES" : @"NO");

[self registerForLocalPlayerAuthChange];

[self initCachedAchievements];}

return self;}

-(void) dealloc{

CCLOG(@"dealloc %@", self);

[instanceOfGameKitHelper release];instanceOfGameKitHelper = nil;

[lastError release];

[self saveCachedAchievements];[cachedAchievements release];[achievements release];

[currentMatch release];

[[NSNotificationCenter defaultCenter] removeObserver:self];

54

Page 55: SG Bienvenida Cocos2D

Slinger studios 2011

[super dealloc];}

#pragma mark setLastError

-(void) setLastError:(NSError*)error{

[lastError release];lastError = [error copy];

if (lastError){

NSLog(@"GameKitHelper ERROR: %@", [[lastError userInfo] description]);}

}

#pragma mark Player Authentication

-(void) authenticateLocalPlayer{

if (isGameCenterAvailable == NO)return;

GKLocalPlayer* localPlayer = [GKLocalPlayer localPlayer];if (localPlayer.authenticated == NO){

// Authenticate player, using a block object. See Apple's Block Programming guide for more info about Block Objects:

// http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Blocks/Articles/00_Introduction.html

[localPlayer authenticateWithCompletionHandler:^(NSError* error){

[self setLastError:error];

if (error == nil){

[self initMatchInvitationHandler];[self reportCachedAchievements];[self loadAchievements];

}}];

/* // NOTE: bad example ahead! // If you want to modify a local variable inside a block object, you have to prefix it with the __block

keyword. __block bool success = NO; [localPlayer authenticateWithCompletionHandler:^(NSError* error) { success = (error == nil); }];

55

Page 56: SG Bienvenida Cocos2D

Slinger studios 2011

// CAUTION: success will always be NO here! The block isn't run until later, when the authentication

call was // confirmed by the Game Center server. Set a breakpoint inside the block to see what is happening in

what order. if (success) NSLog(@"Local player logged in!"); else NSLog(@"Local player NOT logged in!"); */

}}

-(void) onLocalPlayerAuthenticationChanged{

[delegate onLocalPlayerAuthenticationChanged];}

-(void) registerForLocalPlayerAuthChange{

if (isGameCenterAvailable == NO)return;

// Register to receive notifications when local player authentication status changesNSNotificationCenter* nc = [NSNotificationCenter defaultCenter];[nc addObserver:self

selector:@selector(onLocalPlayerAuthenticationChanged) name:GKPlayerAuthenticationDidChangeNotificationName object:nil];

}

#pragma mark Friends & Player Info

-(void) getLocalPlayerFriends{

if (isGameCenterAvailable == NO)return;

GKLocalPlayer* localPlayer = [GKLocalPlayer localPlayer];if (localPlayer.authenticated){

// First, get the list of friends (player IDs)[localPlayer loadFriendsWithCompletionHandler:^(NSArray* friends, NSError* error){

[self setLastError:error];[delegate onFriendListReceived:friends];

}];}

}

-(void) getPlayerInfo:(NSArray*)playerList{

if (isGameCenterAvailable == NO)

56

Page 57: SG Bienvenida Cocos2D

Slinger studios 2011

return;

// Get detailed information about a list of playersif ([playerList count] > 0){

[GKPlayer loadPlayersForIdentifiers:playerList withCompletionHandler:^(NSArray* players, NSError* error)

{[self setLastError:error];[delegate onPlayerInfoReceived:players];

}];}

}

#pragma mark Scores & Leaderboard

-(void) submitScore:(int64_t)score category:(NSString*)category{

if (isGameCenterAvailable == NO)return;

GKScore* gkScore = [[[GKScore alloc] initWithCategory:category] autorelease];gkScore.value = score;

[gkScore reportScoreWithCompletionHandler:^(NSError* error){

[self setLastError:error];

bool success = (error == nil);[delegate onScoresSubmitted:success];

}];}

-(void) retrieveScoresForPlayers:(NSArray*)playerscategory:(NSString*)category range:(NSRange)range

playerScope:(GKLeaderboardPlayerScope)playerScope timeScope:(GKLeaderboardTimeScope)timeScope

{if (isGameCenterAvailable == NO)

return;

GKLeaderboard* leaderboard = nil;if ([players count] > 0){

leaderboard = [[[GKLeaderboard alloc] initWithPlayerIDs:players] autorelease];}else{

leaderboard = [[[GKLeaderboard alloc] init] autorelease];leaderboard.playerScope = playerScope;

}

57

Page 58: SG Bienvenida Cocos2D

Slinger studios 2011

if (leaderboard != nil){

leaderboard.timeScope = timeScope;leaderboard.category = category;leaderboard.range = range;[leaderboard loadScoresWithCompletionHandler:^(NSArray* scores, NSError* error){

[self setLastError:error];[delegate onScoresReceived:scores];

}];}

}

-(void) retrieveTopTenAllTimeGlobalScores{

[self retrieveScoresForPlayers:nil category:nil

range:NSMakeRange(1, 10) playerScope:GKLeaderboardPlayerScopeGlobal

timeScope:GKLeaderboardTimeScopeAllTime];}

#pragma mark Achievements

-(void) loadAchievements{

if (isGameCenterAvailable == NO)return;

[GKAchievement loadAchievementsWithCompletionHandler:^(NSArray* loadedAchievements, NSError* error){

[self setLastError:error]; if (achievements == nil){

achievements = [[NSMutableDictionary alloc] init];}else{

[achievements removeAllObjects];}

for (GKAchievement* achievement in loadedAchievements){

[achievements setObject:achievement forKey:achievement.identifier];} [delegate onAchievementsLoaded:achievements];

}];}

-(GKAchievement*) getAchievementByID:(NSString*)identifier{

58

Page 59: SG Bienvenida Cocos2D

Slinger studios 2011

if (isGameCenterAvailable == NO)return nil;

// Try to get an existing achievement with this identifierGKAchievement* achievement = [achievements objectForKey:identifier];

if (achievement == nil){

// Create a new achievement objectachievement = [[[GKAchievement alloc] initWithIdentifier:identifier] autorelease];[achievements setObject:achievement forKey:achievement.identifier];

}

return [[achievement retain] autorelease];}

-(void) reportAchievementWithID:(NSString*)identifier percentComplete:(float)percent{

if (isGameCenterAvailable == NO)return;

GKAchievement* achievement = [self getAchievementByID:identifier];if (achievement != nil && achievement.percentComplete < percent){

achievement.percentComplete = percent;[achievement reportAchievementWithCompletionHandler:^(NSError* error){

[self setLastError:error];

bool success = (error == nil);if (success == NO){

// Keep achievement to try to submit it later[self cacheAchievement:achievement];

}

[delegate onAchievementReported:achievement];}];

}}

-(void) resetAchievements{

if (isGameCenterAvailable == NO)return;

[achievements removeAllObjects];[cachedAchievements removeAllObjects];

[GKAchievement resetAchievementsWithCompletionHandler:^(NSError* error){

[self setLastError:error];bool success = (error == nil);

59

Page 60: SG Bienvenida Cocos2D

Slinger studios 2011

[delegate onResetAchievements:success];}];

}

-(void) reportCachedAchievements{

if (isGameCenterAvailable == NO)return;

if ([cachedAchievements count] == 0)return;

for (GKAchievement* achievement in [cachedAchievements allValues]){

[achievement reportAchievementWithCompletionHandler:^(NSError* error){

bool success = (error == nil);if (success == YES){

[self uncacheAchievement:achievement];}

}];}

}

-(void) initCachedAchievements{

NSString* file = [NSHomeDirectory() stringByAppendingPathComponent:kCachedAchievementsFile];id object = [NSKeyedUnarchiver unarchiveObjectWithFile:file];

if ([object isKindOfClass:[NSMutableDictionary class]]){

NSMutableDictionary* loadedAchievements = (NSMutableDictionary*)object;cachedAchievements = [[NSMutableDictionary alloc] initWithDictionary:loadedAchievements];

}else{

cachedAchievements = [[NSMutableDictionary alloc] init];}

}

-(void) saveCachedAchievements{

NSString* file = [NSHomeDirectory() stringByAppendingPathComponent:kCachedAchievementsFile];[NSKeyedArchiver archiveRootObject:cachedAchievements toFile:file];

}

-(void) cacheAchievement:(GKAchievement*)achievement{

[cachedAchievements setObject:achievement forKey:achievement.identifier];

// Save to disk immediately, to keep achievements around even if the game crashes.[self saveCachedAchievements];

60

Page 61: SG Bienvenida Cocos2D

Slinger studios 2011

}

-(void) uncacheAchievement:(GKAchievement*)achievement{

[cachedAchievements removeObjectForKey:achievement.identifier];

// Save to disk immediately, to keep the removed cached achievement from being loaded again[self saveCachedAchievements];

}

#pragma mark Matchmaking

-(void) disconnectCurrentMatch{

[currentMatch disconnect];currentMatch.delegate = nil;[currentMatch release];currentMatch = nil;

}

-(void) setCurrentMatch:(GKMatch*)match{

if ([currentMatch isEqual:match] == NO){

[self disconnectCurrentMatch];currentMatch = [match retain];currentMatch.delegate = self;

}}

-(void) initMatchInvitationHandler{

if (isGameCenterAvailable == NO)return;

[GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite* acceptedInvite, NSArray* playersToInvite){

[self disconnectCurrentMatch];

if (acceptedInvite){

[self showMatchmakerWithInvite:acceptedInvite];}else if (playersToInvite){

GKMatchRequest* request = [[[GKMatchRequest alloc] init] autorelease];request.minPlayers = 2;request.maxPlayers = 4;request.playersToInvite = playersToInvite;

[self showMatchmakerWithRequest:request];}

};

61

Page 62: SG Bienvenida Cocos2D

Slinger studios 2011

}

-(void) findMatchForRequest:(GKMatchRequest*)request{

if (isGameCenterAvailable == NO)return;

[[GKMatchmaker sharedMatchmaker] findMatchForRequest:request withCompletionHandler:^(GKMatch* match, NSError* error)

{[self setLastError:error];

if (match != nil){

[self setCurrentMatch:match];[delegate onMatchFound:match];

}}];

}

-(void) addPlayersToMatch:(GKMatchRequest*)request{

if (isGameCenterAvailable == NO)return;

if (currentMatch == nil)return;

[[GKMatchmaker sharedMatchmaker] addPlayersToMatch:currentMatch matchRequest:request completionHandler:^(NSError* error)

{[self setLastError:error];

bool success = (error == nil);[delegate onPlayersAddedToMatch:success];

}];}

-(void) cancelMatchmakingRequest{

if (isGameCenterAvailable == NO)return;

[[GKMatchmaker sharedMatchmaker] cancel];}

-(void) queryMatchmakingActivity{

if (isGameCenterAvailable == NO)return;

[[GKMatchmaker sharedMatchmaker] queryActivityWithCompletionHandler:^(NSInteger activity, NSError* error)

62

Page 63: SG Bienvenida Cocos2D

Slinger studios 2011

{[self setLastError:error];

if (error == nil){

[delegate onReceivedMatchmakingActivity:activity];}

}];}

#pragma mark Match Connection

-(void) match:(GKMatch*)match player:(NSString*)playerID didChangeState:(GKPlayerConnectionState)state{

switch (state){

case GKPlayerStateConnected:[delegate onPlayerConnected:playerID];break;

case GKPlayerStateDisconnected:[delegate onPlayerDisconnected:playerID];break;

}

if (matchStarted == NO && match.expectedPlayerCount == 0){

matchStarted = YES;[delegate onStartMatch];

}}

-(void) sendDataToAllPlayers:(void*)data length:(NSUInteger)length{

if (isGameCenterAvailable == NO)return;

NSError* error = nil;NSData* packet = [NSData dataWithBytes:data length:length];[currentMatch sendDataToAllPlayers:packet withDataMode:GKMatchSendDataUnreliable error:&error];[self setLastError:error];

}

-(void) match:(GKMatch*)match didReceiveData:(NSData*)data fromPlayer:(NSString*)playerID{

[delegate onReceivedData:data fromPlayer:playerID];}

#pragma mark Views (Leaderboard, Achievements)

// Helper methods

-(UIViewController*) getRootViewController{

63

Page 64: SG Bienvenida Cocos2D

Slinger studios 2011

return [UIApplication sharedApplication].keyWindow.rootViewController;}

-(void) presentViewController:(UIViewController*)vc{

UIViewController* rootVC = [self getRootViewController];[rootVC presentModalViewController:vc animated:YES];

}

-(void) dismissModalViewController{

UIViewController* rootVC = [self getRootViewController];[rootVC dismissModalViewControllerAnimated:YES];

}

// Leaderboards

-(void) showLeaderboard{

if (isGameCenterAvailable == NO)return;

GKLeaderboardViewController* leaderboardVC = [[[GKLeaderboardViewController alloc] init] autorelease];if (leaderboardVC != nil){

leaderboardVC.leaderboardDelegate = self;[self presentViewController:leaderboardVC];

}}

-(void) leaderboardViewControllerDidFinish:(GKLeaderboardViewController*)viewController{

[self dismissModalViewController];[delegate onLeaderboardViewDismissed];

}

// Achievements

-(void) showAchievements{

if (isGameCenterAvailable == NO)return;

GKAchievementViewController* achievementsVC = [[[GKAchievementViewController alloc] init] autorelease];if (achievementsVC != nil){

achievementsVC.achievementDelegate = self;[self presentViewController:achievementsVC];

}}

-(void) achievementViewControllerDidFinish:(GKAchievementViewController*)viewController{

64

Page 65: SG Bienvenida Cocos2D

Slinger studios 2011

[self dismissModalViewController];[delegate onAchievementsViewDismissed];

}

// Matchmaking

-(void) showMatchmakerWithInvite:(GKInvite*)invite{

GKMatchmakerViewController* inviteVC = [[[GKMatchmakerViewController alloc] initWithInvite:invite] autorelease];

if (inviteVC != nil){

inviteVC.matchmakerDelegate = self;[self presentViewController:inviteVC];

}}

-(void) showMatchmakerWithRequest:(GKMatchRequest*)request{

GKMatchmakerViewController* hostVC = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease];

if (hostVC != nil){

hostVC.matchmakerDelegate = self;[self presentViewController:hostVC];

}}

-(void) matchmakerViewControllerWasCancelled:(GKMatchmakerViewController*)viewController{

[self dismissModalViewController];[delegate onMatchmakingViewDismissed];

}

-(void) matchmakerViewController:(GKMatchmakerViewController*)viewController didFailWithError:(NSError*)error{

[self dismissModalViewController];[self setLastError:error];[delegate onMatchmakingViewError];

}

-(void) matchmakerViewController:(GKMatchmakerViewController*)viewController didFindMatch:(GKMatch*)match{

[self dismissModalViewController];[self setCurrentMatch:match];[delegate onMatchFound:match];

}

@end

65

Page 66: SG Bienvenida Cocos2D

Slinger studios 2011

Cocos2D integración con redes sociales

• Twitter: MGTwitterEngine API from Matt Gemmell (http://mattgemmell.com/2008/02/22/mgtwitterengine-twitter-from-cocoa).

• Facebook: The official Facebook iOS SDK(http://github.com/facebook/facebook-ios-sdk)

• OpenFeint: Social leaderboard (http:// www.openfeint.com/developers).

• ScoreLoop: Social leaderboard con microtransacciones ( http://www.scoreloop.com)

• Plus+: Red social creada por el reconocido publisher ngmoco (http://plusplus.com/developers).

• Chillingo’s Crystal: Red social del publisher Chillingo ( www.crystalsdk.com)

• Apple’s push notification service: Si no deseamos utilizar los servicios de las redes sociales Apple pone a nuestra disposición un mecanismo de hacer messaging broadcasting. http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Introduction/Introduction.html.

Modos multijugador en cliente-servidor.

Apple limita las conexiones peer-to-peer a 4 para ajustar el ancho de banda.

• Electrotanks’s Electroserver: es un servicio de cliente servidor la versión gratis se limita a 25 usuario por servidor ( www.electrotank.com ).

• Smartfox (www.smartfoxserver.com/products)

Ads and Analytics

• Iad de Apple (http://advertising.apple.com.)

• AdMob for App Developers (www.admob.com/appdevs)

• Flurry Analytics: sólo la parte analítica www.flurry.com/product/analytics/index.html

Juegos basados en Tiles

Los juegos basados en Tiles se dividen en función de las perpestiva en:

• Ortogonales:

• Isometricos (oblicúa):

Cocos2D cuenta con soporta para trabajar con mapas de Tiles generados por Tiled Map Editor (http://t www.mapeditor.org). Esta herramienta genera un fichero TMX que es un xml con la definicion del mapa de tiles.

66

Page 67: SG Bienvenida Cocos2D

Slinger studios 2011

Desde cocos2D cargamos la información del mapa y los layers generados. CCTMXTiledMap tiene una propiedad propertiesForGID que es un diccionario con todos los atributos adicionales definidos en Tiled util para pasar información adicional de los elementos.

CCTMXTiledMap* tileMap = [CCTMXTiledMap tiledMapWithTMXFile:@"orthogonal.tmx"];[self addChild:tileMap z:-1 tag:TileMapNode];

//Layer GameEventLayer is used to bound touchable elements, nothing to renderCCTMXLayer* eventLayer = [tileMap layerNamed:@"GameEventLayer"];eventLayer.visible = NO;

-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ CCNode* node = [self getChildByTag:TileMapNode]; NSAssert([node isKindOfClass:[CCTMXTiledMap class]], @"not a CCTMXTiledMap"); CCTMXTiledMap* tileMap = (CCTMXTiledMap*)node; // Get the position in tile coordinates from the touch location CGPoint touchLocation = [self locationFromTouches:touches]; CGPoint tilePos = [self tilePosFromLocation:touchLocation tileMap:tileMap]; // Check if the touch was on water (e.g., tiles with isWater property) bool isTouchOnWater = NO; CCTMXLayer* eventLayer = [tileMap layerNamed:@"GameEventLayer"]; int tileGID = [eventLayer tileGIDAt:tilePos]; if (tileGID != 0) { NSDictionary* properties = [tileMap propertiesForGID:tileGID]; if (properties) { NSString* isWaterProperty = [properties valueForKey:@"isWater"]; isTouchOnWater = ([isWaterProperty boolValue] == YES); } }

// Decide what to do depending on where the touch was if (isTouchOnWater) { [[SimpleAudioEngine sharedEngine] playEffect:@"alien-sfx.caf"]; } else { // Get the winter layer and toggle its visibility CCTMXLayer* winterLayer = [tileMap layerNamed:@"WinterLayer"]; winterLayer.visible = !winterLayer.visible; }}

Un aspecto importante de este tipo de juegos es determinar en base a un punto de pantalla la celda afectada

// Get the position in tile coordinates from the touch locationCGPoint touchLocation = [self locationFromTouches:touches];CGPoint tilePos = [self tilePosFromLocation:touchLocation tileMap:tileMap];

67

Page 68: SG Bienvenida Cocos2D

Slinger studios 2011

-(CGPoint) locationFromTouch:(UITouch*)touch{ CGPoint touchLocation = [touch locationInView: [touch view]]; return [[CCDirector sharedDirector] convertToGL:touchLocation];}

-(CGPoint) locationFromTouches:(NSSet*)touches{ return [self locationFromTouch:[touches anyObject]];}

-(CGPoint) tilePosFromLocation:(CGPoint)location tileMap:(CCTMXTiledMap*)tileMap{ // Tilemap position must be subtracted, in case the tilemap is scrolling CGPoint pos = ccpSub(location, tileMap.position); // Cast to int makes sure that result is in whole numbers pos.x = (int)(pos.x / tileMap.tileSize.width); pos.y = (int)((tileMap.mapSize.height * tileMap.tileSize.height - pos.y) / tileMap.tileSize.height); CCLOG(@"touch at (%.0f, %.0f) is at tileCoord (%i, %i)", location.x, location.y, (int)pos.x, (int)pos.y); NSAssert(pos.x >= 0 && pos.y >= 0 && pos.x < tileMap.mapSize.width &&pos.y < tileMap.mapSize.height, @"%@: coordinates (%i, %i) out of bounds!",NSStringFromSelector(_cmd), (int)pos.x, (int)pos.y);return pos;}// CAPA DE OBJECTSCCTMXObjectGroup* objectLayer = [tileMap objectGroupNamed:@"ObjectLayer"];bool isTouchInRectangle = NO;int numObjects = [objectLayer.objects count];for (int i = 0; i < numObjects; i++){ NSDictionary* properties = [objectLayer.objects objectAtIndex:i]; CGRect rect = [self getRectFromObjectProperties:properties tileMap:tileMap]; if (CGRectContainsPoint(rect, touchLocation)) { isTouchInRectangle = YES; break; }}

Es raro caso el mapa de tiles es del tamaño de la pantalla es habitual tener que hacer scroll del mapa

-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{... // Get the position in tile coordinates from the touch location CGPoint touchLocation = [self locationFromTouches:touches]; CGPoint tilePos = [self tilePosFromLocation:touchLocation tileMap:tileMap]; // Move tilemap so that the touched tile is at the center of the screen [self centerTileMapOnTileCoord:tilePos tileMap:tileMap];...}

68

Page 69: SG Bienvenida Cocos2D

Slinger studios 2011

-(void) centerTileMapOnTileCoord:(CGPoint)tilePos tileMap:(CCTMXTiledMap*)tileMap{ // Center tilemap on the given tile pos CGSize screenSize = [[CCDirector sharedDirector] winSize]; CGPoint screenCenter = CGPointMake(screenSize.width * 0.5f, screenSize.height * 0.5f); // Tile coordinates are counted from upper-left corner tilePos.y = (tileMap.mapSize.height - 1) - tilePos.y; // Point is now at lower-left corner of the screen CGPoint scrollPosition = CGPointMake(-(tilePos.x * tileMap.tileSize.width),-(tilePos.y * tileMap.tileSize.height)); // Offset point to center of screen and center of tile scrollPosition.x += screenCenter.x - tileMap.tileSize.width * 0.5f; scrollPosition.y += screenCenter.y - tileMap.tileSize.height * 0.5f; // Make sure tilemap scrolling stops at the tilemap borders scrollPosition.x = MIN(scrollPosition.x, 0); scrollPosition.x = MAX(scrollPosition.x, -screenSize.width); scrollPosition.y = MIN(scrollPosition.y, 0); scrollPosition.y = MAX(scrollPosition.y, -screenSize.height); CCAction* move = [CCMoveTo actionWithDuration:0.2f position: scrollPosition]; [tileMap stopAllActions]; [tileMap runAction:move];}

Mezclado código Cocos2D y Gl en el método draw de CCNode

-(void) draw{ CCNode* node = [self getChildByTag:TileMapNode]; NSAssert([node isKindOfClass:[CCTMXTiledMap class]], @"not a CCTMXTiledMap"); CCTMXTiledMap* tileMap = (CCTMXTiledMap*)node; // Get the object layer CCTMXObjectGroup* objectLayer = [tileMap objectGroupNamed:@"ObjectLayer"];

// Make the line 3 pixels thick glLineWidth(3.0f); glColor4f(1, 0, 1, 1);

int numObjects = [[objectLayer objects] count]; for (int i = 0; i < numObjects; i++) { NSDictionary* properties = [[objectLayer objects] objectAtIndex:i]; CGRect rect = [self getRectFromObjectProperties:propertiestileMap:tileMap]; [self drawRect:rect];}

glLineWidth(1.0f);glColor4f(1, 1, 1, 1);}

Nota: GL es una máquina de estado es importante seguir el patron de guardar-estado, dibujar en cocos2D y restaurar estado!!!

69

Page 70: SG Bienvenida Cocos2D

Slinger studios 2011

CCDrawingPrimitives.h para dibujar primitivas

• 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)

70