Construye un juego de Monster Smashing con Cocos2D Mecánica de sonido y juegos

Este tutorial le enseñará cómo usar el marco de trabajo de Cocos2D para crear juegos 2D simples pero avanzados dirigidos a todos los dispositivos iOS. Está diseñado para usuarios principiantes y avanzados. En el camino, aprenderá acerca de los conceptos básicos de Cocos2D, la interacción táctil, los menús y las transiciones, las acciones, las partículas y las colisiones. Sigue leyendo!


Organización de la serie:
  • Estructura y configuración del proyecto
  • Movimiento y animaciones
  • Mecánica de sonido y juegos

Esta entrada es el tercer y último tutorial de la serie. Monster Smashing. Asegúrate de haber completado el tutorial anterior antes de comenzar.

En el tutorial de hoy, nos centraremos en terminar el juego. Agregaremos varias propiedades, incluyendo partículas, etiquetas, sonido y música. Usaremos la lista de propiedades para la creación de monstruos. También aprenderemos cómo pausar y reanudar correctamente el proceso de flujo de datos de Cocos2D sin demasiada capacidad de procesamiento.


1. vidas

El sistema de etiquetas en los juegos se usa normalmente para puntajes, vidas u otra información relacionada. En este tutorial solo usaremos vidas de jugadores. Cada vida se representa con un corazón en la parte superior izquierda de la pantalla. La imagen del corazón está en los recursos..

El usuario comenzará el juego con tres vidas. Para hacer esto, inicializamos el HeartArray y usamos el para Bucle para recibir las imágenes de cada vida. También establecemos la posición de las tres vidas en la parte superior izquierda de la pantalla.

El primer paso es agregar dos nuevas propiedades., NSMutableArray * hearthArray y NSInteger vive, al MonsterRun.h clase. Con eso hecho ahora podemos agregar la implementación correcta., MonstrRun.m. El siguiente fragmento de código nos ayudará a hacer eso..

 vidas = 3; hearthArray = [[NSMutableArray alloc] init]; para (NSInteger i = 0; vivo; i ++) CCSprite * hearth = [CCSprite spriteWithFile: @ "hearth.png"]; [hearthArray insertObject: hearth atIndex: i]; hearth.position = ccp (((i + 1) * 50), winSize.height - 50); [auto addChild: hogar]; 

Ahora, si ejecuta el proyecto, verá las vidas en la parte superior de la pantalla. Sin embargo, todavía no podemos interactuar con ellos. El siguiente paso es interactuar con ellos y hacer que el jugador pierda algunas vidas..

En el metodo addMonster: (ccTime) dt en la sección del Bloque 4 dentro de la CCCallBlockN Función, deberíamos añadir el siguiente fragmento de código..

 vive--; [self removeChild: [hearthArray lastObject] limpieza: YES]; [hearthArray removeLastObject]; if (lives == 0) [[CCDirector sharedDirector] replaceScene: [HelloWorldLayer scene]];

Tenga en cuenta que debe agregarlo dos veces, uno para cada Si declaración.

El código se llamará cada vez que un sprite (monstruo) salga de la pantalla. Si un monstruo abandona la pantalla, se perderá una vida y, al mismo tiempo, se cambiará la matriz de corazones (HeartArray) y se eliminará la última posición. La imagen en pantalla también será eliminada..

Si llegamos a cero vidas, el juego se detendrá y volveremos a la pantalla inicial..


2. Partículas

Las partículas son un efecto utilizado para lograr, entre otras cosas, varios efectos como el fuego, el humo o las cascadas. En este caso, los usaremos para explotar el monstruo rojo. Cada vez que un monstruo rojo es tocado, activamos la partícula..

En la segunda parte, dejamos esa sección incompleta. Ahora es el momento de terminarlo..

Añade la siguiente propiedad CCPartículaExplosión * PartículaExplosión al MonsterRun.h clase. En el -(void) ccTouchesBegan: (NSSet *) toca conEvent: (UIEvent *) event método, donde tenemos el si ([m killMethod] == 2) Condición, añadiremos un nuevo código..

 CCCallFuncND * emitter = [CCCallFuncND actionWithTarget: self selector: @selector (startExplosion: data :) data: monster]; CCSequence * sequencia = [CCSequence actions: emitter, nil]; if ([por defecto integerForKey: @ "sound"] == 1) [[SimpleAudioEngine sharedEngine] playEffect: @ "SplatEffect.caf"]; [splashPool runAction: sequencia]; [/ sourcecode] Este código proporcionará los requisitos necesarios para el sistema de partículas. Primero usamos el CCCallFuncND llamar a un selector startExplosion: datos:. Luego creamos una secuencia de partículas que llama a la mención anterior "emisor"objeto. El siguiente paso es crear el CCPartículaExplosión * PartículaExplosión método. Para eso puedes simplemente copiar y pegar el siguiente fragmento de código. [sourcecode language = "object c"] [/ sourcecode] // Coloca el emisor de explosión y lo desactiva - (void) startExplosion: (id) sender data: (CCSprite *) monster particleExplosion = [[CCParticleExplosion alloc] initWithTotalParticles: 809]; particleExplosion.texture = [[CCTextureCache sharedTextureCache] addImage: @ "textureRed.png"]; partículaExplosión.vida = 0.0f; particleExplosion.lifeVar = 0.708f; particleExplosion.startSize = 40; particleExplosion.startSizeVar = 38; particleExplosion.endSize = 14; particleExplosion.endSizeVar = 0; particleExplosion.angle = 360; particleExplosion.angleVar = 360; particleExplosion.speed = 243; particleExplosion.speedVar = 1; CGPoint g = CGPointMake (1.15, 1.58); partículaExplosióngravidad = g; ccColor4F startC = 0.89f, 0.56f, 0.36f, 1.0f; particleExplosion.startColor = startC; ccColor4F endC = 1.0f, 0.0f, 0.0f, 1.0f; particleExplosion.endColor = endC; [auto addChild: particleExplosion]; particleExplosion.position = [posición del monstruo]; [Sistema de restablecimiento de partículas de explosión]; 

Este metodo

  • Asignar para el PartículaExplosión propiedad.
  • Definir el recuento total de partículas (809).
  • Definir la textura de las partículas (CCTextureCache)
  • Defina varias propiedades, como tamaño de inicio y final, ángulo, velocidad y color.

Una vez configurada la partícula, podemos colocarla en el centro del monstruo. La explosión de partículas siempre se moverá cuando el monstruo se esté moviendo, y siempre estará centrada.

Ahora puedes construir y ejecutar el proyecto. Un ejemplo de la explosión de partículas se puede ver en la siguiente imagen..

Ilustración del sistema de partículas..

3. Sonido y música.

Los efectos de sonido y la música de fondo son activos para todos los juegos. En esta sección, explicaremos cómo agregarlos a este juego. Tendremos dos tipos de sonidos, un clic de monstruo y la música de fondo..

El audio en dispositivos iOS se logra utilizando el motor de audio simple. Para activarlo, importa el SimpleAudioEngine.h en el HelloWorldLayer.m y MonsterRun.m clases.

En el HelloWorldLayer.m, Tenemos varios pasos para hacer. El primero es agregar el CCMenuItem * _soundOn propiedad antes de la @implementación sección.

Debe tener un aspecto como este:

 #import "HelloWorldLayer.h" #import "AppDelegate.h" #import "MonsterRun.h" #import "SimpleAudioEngine.h" CCMenuItem * _soundOn; // Implementación de HelloWorldLayer @ Implementación HelloWorldLayer ... 

Ahora podemos pasar a la -(id) init método. Elegimos usar el NSUserDefaults Clase para ayudarnos a almacenar las preferencias del usuario con respecto a la opción de sonido. Primero definiremos un número con el 1 valor (con sonido) y guárdelo utilizando el "sonar". El siguiente paso es verificar el valor de"sonar", y reaccione en consecuencia a ese valor. Si el valor es 1, Se inicializa el sistema de sonido. De lo contrario, permanece en pausa..

El siguiente fragmento muestra esta implementación.

 // Compruebe el sistema de sonido NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; NSObject * object = [defaults objectForKey: @ "sound"]; if (object == nil) NSNumber * soundValue = [[NSNumber alloc] initWithInt: 1]; [por defecto setObject: soundValue forKey: @ "sound"];  int soundDefault = [por defecto integerForKey: @ "sound"]; if (soundDefault == 1) [[SimpleAudioEngine sharedEngine] playBackgroundMusic: @ "backgroundSound.caf"]; [[SimpleAudioEngine sharedEngine] setEffectsVolume: 0.4f];  else [[SimpleAudioEngine sharedEngine] pauseBackgroundMusic]; 

Ahora puedes modificar el CCMenuItemToggle * toggleItem.

 CCMenuItemToggle * toggleItem; if (soundDefault == 1) toggleItem = [CCMenuItemToggle itemWithTarget: self selector: @selector (soundButtonTapped :) items: _soundOn, _soundOff, nil]; else toggleItem = [CCMenuItemToggle itemWithTarget: self selector: @selector (soundButtonTapped :) items: _soundOff, _soundOn, nil];

Con este cambio, el menú cambiará de acuerdo con las preferencias de sonido del usuario. Tenga en cuenta que el toggleItem llama a un selector SoundButtonTapped:, así que tendremos que escribir ese método y crear la lógica correcta para verificar el botón de alternar. Si el botón de alternar está seleccionado para _sonido encendido, Deberíamos empezar a sonar y almacenar. 1 en el NSUserDefaults preferencias Si el botón de alternar está seleccionado para _sonido apagado, Debemos pausar la música de fondo y la tienda. 0 en el NSUserDefaults preferencias.

Use el siguiente fragmento de código para ese efecto.

 - (void) soundButtonTapped: (id) sender CCMenuItemToggle * toggleItem = (CCMenuItemToggle *) sender; if (toggleItem.selectedItem == _soundOn) NSLog (@ "Sound Enabled"); NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; [[SimpleAudioEngine sharedEngine] playBackgroundMusic: @ "backgroundSound.caf"]; [por defecto setInteger: 1 forKey: @ "sound"]; [los valores predeterminados sincronizan];  else NSLog (@ "Sound Disabled"); NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; [por defecto setInteger: 0 forKey: @ "sound"]; [[SimpleAudioEngine sharedEngine] pauseBackgroundMusic]; [los valores predeterminados sincronizan]; 

Ahora también debemos cambiar el MonsterRun.m clase. Debemos agregar el Valores predeterminados de NSUserDefaults *; propiedad global. A continuación, lo inicializaremos y verificaremos las preferencias de sonido del usuario. El siguiente fragmento de código nos ayudará a lograrlo..

 - (void) soundButtonTapped: (id) sender defaults = [NSUserDefaults standardUserDefaults]; int soundDefault = [predeterminados integerForKey: @ "sound"]; if (soundDefault == 1) [[SimpleAudioEngine sharedEngine] playBackgroundMusic: @ "backgroundSound.caf"]; [[SimpleAudioEngine sharedEngine] setEffectsVolume: 0.4f]; 

Con este código podemos agregar un sonido de fondo y una forma para que el usuario lo controle utilizando las preferencias predeterminadas del sistema. Ahora puede ejecutar el proyecto y jugar con el botón de sonido para probar la nueva propiedad de sonido.


4. Lista de propiedades

Listas de propiedades (plist) son un recurso útil para almacenar información sobre el entorno y la evolución del juego. En nuestro caso, almacenaremos información sobre los monstruos. El plist creado (Enemy.plist) Se puede ver en la siguiente imagen..

Ilustración del enemigo plist.

No discutiremos la mejor manera de crear o analizar el plist. Nos centraremos en este error y en una posible forma de analizar los datos a partir de él..

El primer paso es agregar el plist al proyecto. Hacer clic Archivo -> Nuevo -> Archivo y elija desde el lado derecho el recurso de opción y luego la lista de propiedades (a la izquierda). Nombralo Enemy.plist Y añada la información de la imagen anterior..

Ahora debemos analizar los datos y usarlos para crear los monstruos con esa información. Primero creamos una cadena con la ruta al archivo plist, y luego creamos un diccionario que almacenará la información dentro de la lista. El último paso es recuperar las opciones del monstruo. Para cada monstruo, les agregaremos esas mismas propiedades..

 // plist reading NSString * plistPath = [[NSBundle mainBundle] pathForResource: @ "Enemy" ofType: @ "plist"]; NSMutableDictionary * dictionary = [[NSMutableDictionary alloc] initWithContentsOfFile: plistPath]; // carga la información del monstruo desde pList if ([dictionary objectForKey: @ "Monsters"]! = nil) NSMutableArray * array = [dictionary objectForKey: @ "Monsters"]; para (int i = 0; i < [array count]; i++) NSMutableDictionary *m = [array objectAtIndex:i]; Monster *m1 = [[Monster alloc] init]; [m1 setTag:(i+1)]; [m1 setMonsterSprite:[[NSString alloc] initWithString:[m objectForKey:@"monsterSprite"]]]; [m1 setSplashSprite:[[NSString alloc] initWithString:[m objectForKey:@"splashSprite"]]]; [m1 setMinVelocity:[[m objectForKey:@"minVelocity"] floatValue]]; [m1 setMaxVelocity:[[m objectForKey:@"maxVelocity"] floatValue]]; [m1 setMovement:[[m objectForKey:@"movement"] intValue]]; [m1 setKillMethod:[[m objectForKey:@"killMethod"] intValue]]; [_monsters addObject:m1];  

Lo nuevo y definitivo. -(id) init El método debería verse así.

 -(id) init if ((self = [super init])) self.isTouchEnabled = YES; CGSize winSize = [CCDirector sharedDirector] .winSize; CCSprite * dirt = [CCSprite spriteWithFile: @ "WoodRetroApple_iPad_HomeScreen.jpg"]; dirt.position = ccp (winSize.width / 2, winSize.height / 2); [auto addChild: dirt z: -2]; _monsters = [[NSMutableArray alloc] init]; // plist reading NSString * plistPath = [[NSBundle mainBundle] pathForResource: @ "Enemy" ofType: @ "plist"]; NSMutableDictionary * dictionary = [[NSMutableDictionary alloc] initWithContentsOfFile: plistPath]; // carga la información del monstruo desde pList if ([dictionary objectForKey: @ "Monsters"]! = nil) NSMutableArray * array = [dictionary objectForKey: @ "Monsters"]; para (int i = 0; i < [array count]; i++) NSMutableDictionary *m = [array objectAtIndex:i]; Monster *m1 = [[Monster alloc] init]; [m1 setTag:(i+1)]; [m1 setMonsterSprite:[[NSString alloc] initWithString:[m objectForKey:@"monsterSprite"]]]; [m1 setSplashSprite:[[NSString alloc] initWithString:[m objectForKey:@"splashSprite"]]]; [m1 setMinVelocity:[[m objectForKey:@"minVelocity"] floatValue]]; [m1 setMaxVelocity:[[m objectForKey:@"maxVelocity"] floatValue]]; [m1 setMovement:[[m objectForKey:@"movement"] intValue]]; [m1 setKillMethod:[[m objectForKey:@"killMethod"] intValue]]; [_monsters addObject:m1];   lives = 3; hearthArray = [[NSMutableArray alloc] init]; for(NSInteger i = 0; i lives; i++) CCSprite *hearth = [CCSprite spriteWithFile:@"hearth.png"]; [hearthArray insertObject:hearth atIndex:i]; hearth.position = ccp( ((i+1)*50), winSize.height - 50); [self addChild:hearth];  CCMenuItem *pauseButton = [CCMenuItemImage itemFromNormalImage:@"pauseButton.png" selectedImage:@"pauseButton.png" target:self selector:@selector(plusMinusButtonTapped:)]; pauseButton.position = ccp(winSize.width - 50 , winSize.height - 50 ); pauseMenu = [CCMenu menuWithItems:pauseButton, nil]; pauseMenu.position = CGPointZero; [self addChild:pauseMenu]; [self schedule:@selector(addMonster:) interval:0.5]; _monstersOnScreen = [[NSMutableArray alloc] init]; defaults = [NSUserDefaults standardUserDefaults]; int soundDefault = [defaults integerForKey:@"sound"]; if (soundDefault == 1)  [[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"backgroundSound.caf"]; [[SimpleAudioEngine sharedEngine] setEffectsVolume:0.4f];   return self; 

Tenga en cuenta que los errores deben utilizarse sobre otros métodos de almacenamiento, ya que iOS está optimizado para leerlos, escribirlos y procesarlos..


5. Pausa y reanudar

Las opciones de pausa y reanudar son dos opciones muy importantes, ya que el juego no siempre se ejecutará. La pausa y reanudación correctas ahorrarán la vida de la batería y harán que su código esté orientado al rendimiento.

El primer paso es agregar otra clase llamada Pausa.

los .h debe verse como

 #importar  #importar "cocos2d.h" @interface PausedScene: CCScene  + (CCScene *) scene; @fin

mientras que la implementación se verá como:

 #import "PausedScene.h" #import "MonsterRun.h" #import "HelloWorldLayer.h" @implementation PausedScene + (CCScene *) scene CCScene * scene = [CCScene node]; PausedScene * layer = [nodo de PausedScene]; [escena addChild: capa]; escena de retorno  - (id) init if ((self = [super init])) CGSize winSize = [CCDirector sharedDirector] .winSize; CCSprite * background = [CCSprite spriteWithFile: @ "WoodRetroApple_iPad_HomeScreen.jpg"]; background.position = ccp (winSize.width / 2, winSize.height / 2); [auto addChild: background z: -2]; CCSprite * logo = [CCSprite spriteWithFile: @ "MonsterSmashing.png"]; logo.scale = 1.2; logo.position = ccp (winSize.width / 2, 800); [auto addChild: logo]; CCMenuItem * resumeGameButtonImage = [CCMenuItemImage itemFromNormalImage: @ "resume.png" selectedImage: @ "resume.png" target: selector automático: @selector (onStartGamePressed)]; CCMenuItem * exitGameButtonImage = [CCMenuItemImage itemFromNormalImage: @ "exit.png" selectedImage: @ "exit.png" target: selector automático: @selector (mainMenuPressed)]; CCMenu * menu = [CCMenu menuWithItems: resumeGameButtonImage, exitGameButtonImage, nil]; menu.position = ccp (winSize.width * 0.5f, winSize.height * 0.4f); [menú alignItemsVerticallyWithPadding: 15]; [auto addChild: menu];  devuélvete a ti mismo;  - (void) mainMenuPressed CCScene * menuScene = [HelloWorldLayer scene]; [[CCDirector sharedDirector] replaceScene: menuScene];  - (void) onStartGamePressed [[CCDirector sharedDirector] popScene];  - (void) dealloc [super dealloc];  @final

En este punto, el código debe explicarse por sí mismo con la excepción del - (void) onStartGamePressed método. Sin embargo, ese método es bastante simple. Se "abrirá" una pantalla y hará que la última pantalla sea visible.

En MonsterRun.h, añade el CCMenu * pauseMenu; propiedad. los MonsterRun.m El código ya está completo, por lo que veremos las siguientes líneas.

 CCMenuItem * pauseButton = [CCMenuItemImage itemFromNormalImage: @ "pauseButton.png" selectedImage: @ "pauseButton.png" target: auto selector: @selector (plusMinusButtonTapped :)]; pauseButton.position = ccp (winSize.width - 50, winSize.height - 50); pauseMenu = [CCMenu menuWithItems: pauseButton, nil]; pauseMenu.position = CGPointZero;

Los códigos de método significan que para un determinado CCMenuItem, agregaremos una imagen (disponible en los recursos), un selector y una posición.

los - (void) plusMinusButtonTapped El método se llama cada vez que se toca el menú de pausa. Si el juego no está pausado, "empujará" una nueva escena, el PauseScene, En la pantalla y pausar el juego. Si el juego está en pausa, reanudará la animación y verificará si puede comenzar a verificar los valores predeterminados del usuario.

 - (void) plusMinusButtonTapped: (id) sender if (! [[CCDirector sharedDirector] está en pausa]) [self pauseSchedulerAndActions]; CCScene * menuScene = [PausedScene scene]; [[CCDirector sharedDirector] pushScene: menuScene];  else [[CCDirector sharedDirector] stopAnimation]; [[CCDirector sharedDirector] resume]; [[CCDirector sharedDirector] startAnimation]; int soundDefault = [predeterminados integerForKey: @ "sound"]; if (soundDefault == 1) [[SimpleAudioEngine sharedEngine] resumeBackgroundMusic]; 

La siguiente imagen presenta el menú de pausa con dos opciones, reanudar y salir. La reanudación devolverá al jugador al tablero de juego, mientras que la salida llevará al usuario al menú principal.

Ilustración del menú de pausa..

6. Resultados

La siguiente imagen presenta la versión final de la interfaz de juego..

Ilustración de juego.

La siguiente imagen presenta la versión final del menú principal..

Ilustración del menú principal.

En este punto, debe poder comprender y realizar las siguientes tareas:

  • Añadir etiquetas personalizadas.
  • Utilizar, definir y añadir el sistema de partículas..
  • Añadir sonido personalizado y música de fondo.
  • NSUserDefaults y SimpleAudioEngine conocimiento
  • Utilice plistas simples o avanzadas.
  • Pausa y reanudación de los mecanismos de Cocos2D..
  • Saber como crear un juego..

7. Notas

Los autores han realizado trabajos adicionales, que se resumen a continuación:

  • Fondo personalizado.
  • Personalización del icono de la aplicación (utilizando las directrices de Apple)..
  • Cambiar el nombre de la aplicación que aparece en el dispositivo o emulador, eliminando los puntos en el nombre si ese nombre es demasiado largo.

Con esto concluye el tercer y último tutorial que muestra cómo crear un juego Monster Smasher usando Cocos2D. A estas alturas, deberías tener suficiente conocimiento para crear un juego simple de Cocos2D con el mismo motor de juego. Si tiene preguntas o comentarios, no dude en dejarlos en la sección de comentarios aquí..