Cómo hacer un tirador de desplazamiento multidireccional && num; 8211 & semi; Parte 2

April 1|6 Vistas|

Resumen: Si eres nuevo aquí, tal vez quieras suscribirte a mi feed RSS o seguirme en Twitter. ¡Gracias por su visita! Aprende a hacer un juego de disparos de tanques multi-scrolling! Esta es una serie de tutoriales de varias partes en la que te mostramos cómo

Advertisement

Si eres nuevo aquí, tal vez quieras suscribirte a mi feed RSS o seguirme en Twitter. ¡Gracias por su visita!

Cómo hacer un tirador de desplazamiento multidireccional && num; 8211 & semi;  Parte 2

Aprende a hacer un juego de disparos de tanques multi-scrolling!

Esta es una serie de tutoriales de varias partes en la que te mostramos cómo hacer un fresco juego de batalla de tanques multidireccional para el iPhone.

En la primera parte de la serie, creamos un nuevo proyecto de Cocos2D 2.0 con soporte de ARC, agregamos nuestro mapa de azulejos al juego y añadimos un tanque que podríamos mover con el acelerómetro.

En esta segunda y última parte del tutorial, haremos que nuestro tanque dispare balas, agregue tanques enemigos, añada una lógica de ganar / perder, y añada un poco de pulido y toques finales.

Este proyecto comienza donde lo dejamos la última vez, así que agarra el proyecto donde lo dejamos fuera la última vez si no lo tienes ya.

Entonces, ¿haremos un juego?

Correr y Gunning

Ahora nuestro tanque puede moverse, pero no puede disparar! Dado que disparar a los tanques como comprar zapatos es a mi encantadora esposa, es mejor arreglar esto lo antes posible;]

Ya lo hicimos para que el tanque se mueva con el acelerómetro, así que estamos libres para hacer que el tanque dispare dondequiera que el usuario toque. Sin embargo, para hacer el juego más divertido, en lugar de sólo disparar una vez cuando el usuario grifos, vamos a hacer el tanque disparar continuamente!

Así que modifiquemos nuestra clase Tank para añadir algunos métodos para disparar. Realice los cambios siguientes en Tank.h:

  // Añadir dentro @interface CGPoint _shootVector;  Doble _timeSinceLastShot;  CCSprite * _turret;  // Añadir después de @interface @property (asignar) BOOL shooting;  - (void) shootToward: (CGPoint) targetPosition;  - (void) shootNow; 

Aquí añadimos una variable de instancia para seguir la dirección en la que estamos rodando, y cuánto tiempo ha pasado desde la última toma. ¡También seguimos un nuevo sprite que agregaremos encima del tanque - la torreta del tanque!

A continuación, abra Tank.m y realice los siguientes cambios:

  // Añadir al principio del archivo #import "SimpleAudioEngine.h" // Añadir justo después de @implementation @synthesize shooting = _shooting;  // Añadir dentro de initWithLayer: type: hp NSString * turretName = [NSString stringWithFormat: @ "tanque% d_turret.png", escriba];  _turret = [spriteWithSpriteFrameName de CCSprite: nombre de torreta];  _turret.anchorPoint = ccp (0,5, 0,25);  _turret.position = ccp (self.contentSize.width / 2, self.contentSize.height / 2);  [Self addChild: _turret]; 

Firt sintetizamos nuestras variables. A continuación, creamos un nuevo sprite para la torreta del tanque, y lo añadimos como un niño del tanque. Esto es para que cuando movamos el sprite del tanque, la torreta se mueve junto con él.

Observe cómo colocamos la torreta:

  • Modificamos el punto de anclaje para que esté muy cerca de la base de la torreta. ¿Por qué? Porque cualquiera que sea el punto de anclaje es el punto donde la rotación está alrededor, y queremos que la torreta gire alrededor de su base.
  • A continuación, establecer la posición de la sprite para ser el centro del tanque. Dado que este sprite es un niño del tanque, su posición es relativa a la esquina inferior izquierda del tanque. Así que estamos "fijando" el punto de anclaje (la base de la torreta) a alrededor del centro del tanque.

A continuación, agregue un nuevo método al final del archivo:

  - (void) shootToward: (CGPoint) targetPosition {CGPoint offset = ccpSub (posición de destino, posición propia);  Float MIN_OFFSET = 10;  If (ccpLength (offset) <MIN_OFFSET) return;  _shootVector = ccpNormalize (offset);  } 

Llamaremos a este método cuando el usuario toque un punto. Comprobamos para asegurarse de que el punto tapped es por lo menos 10 puntos de la posición actual en primer lugar (si está demasiado cerca, es difícil saber dónde el usuario realmente quiere disparar). Entonces normalizamos el vector (recuerde, esto hace que un vector de longitud uno) por lo que tenemos un vector en la dirección en la que queremos rodar, y almacenar que para referencia futura.

Agregue el método para disparar en el siguiente:

  - (void) shootNow {// 1 CGFloat angle = ccpToAngle (_shootVector);  _turret.rotation = (-1 * CC_RADIANS_TO_DEGREES (ángulo)) + 90;  // 2 float mapMax = MAX ([_ layer tileMapWidth], [_layer tileMapHeight]);  CGPoint realVector = ccpMult (_shootVector, mapMax);  // 3 float POINTS_PER_SECOND = 300;  Float duration = mapMax / POINTS_PER_SECOND;  // 4 NSString * shootSound = [NSString stringWithFormat: @ "tanque% dShoot.wav", _type];  [[SimpleAudioEngine sharedEngine] playEffect: shootSound];  // 5 NSString * bulletName = [NSString stringWithFormat: @ "tanque% d_bullet.png", _type];  CCSprite * bullet = [CCSprite spriteWithSpriteFrameName: bulletName];  Bullet.tag = _type;  Bullet.position = ccpAdd (self.position, ccpMult (_shootVector, _turret.contentSize.height));  CCMoveBy * move = [CCMoveBy actionWithDuration: duration position: realVector];  CCCallBlockN * call = [CCCallBlockN actionWithBlock: ^ (nodo CCNode *) {[node removeFromParentAndCleanup: YES];  }];  [Bullet runAction: [acciones de CCSequence: mover, llamar, nil]];  [_layer.batchNode addChild: viñeta];  } 

Hay un montón de código aquí, así que vamos a repasarlo poco a poco.

  1. En primer lugar girar la torreta para hacer frente en la dirección que queremos disparar. Hay una función práctica llamada ccpToAngle que podemos usar que toma un vector y devuelve el ángulo del vector en radianes. A continuación, convertir esto en grados (que utiliza Cocos2D), multiplíquelo por -1 porque Cocos2D utiliza rotación en sentido horario. También añadimos 90, lo que tenemos que hacer porque nuestra obra de arte de la torre está mirando hacia arriba (en lugar de a la derecha).
  2. A continuación, averiguar qué tan lejos queremos disparar la bala. Básicamente queremos disparar un largo camino, por lo que obtener el máximo de la anchura del mapa de azulejos o la altura y se multiplica por la dirección que queremos disparar.
  3. A continuación, averiguar cuánto tiempo debe tomar la bala para llegar a ese lugar. Esto es simple: dividimos la longitud del vector (el máximo de la anchura o altura del mapa del mosaico) y lo dividimos por los puntos por segundo que queremos que la bala se mueva.
  4. Efecto de sonido de disparo gratuito! :]
  5. Finalmente creamos un nuevo sprite de viñeta, ejecutamos una acción en él para hacer que se mueva (y desaparezca al finalizar el movimiento) y lo añadamos al nodo de lote de la capa.

Luego haga estos cambios en Tank.m:

  // Añadir nuevos métodos - (BOOL) shouldShoot {if (! Self.shooting) devolver NO;  Doble SECS_BETWEEN_SHOTS = 0,25;  If (_timeSinceLastShot> SECS_BETWEEN_SHOTS) {_timeSinceLastShot = 0;  Devolver SI;  } Else {return NO;  }} - (void) updateShoot: (ccTime) dt {_timeSinceLastShot + = dt;  If ([self shouldShoot]) {[self shootNow];  }} // Añadir dentro de la actualización [auto updateShoot: dt]; 

Este es el código que necesitamos para que los tanques disparen continuamente. Cada bucle de actualización lo llamaremos updateShoot. Esto solo comprueba si ha estado por lo menos 0,25 segundos desde el último disparo, y las llamadas dispararonNueve, si es así.

OK, finalmente hecho con Tank.m! Vamos a probar esto. Abra HelloWorldLayer.m y reemplace ccTouchesBegan y ccTouchesMoved con lo siguiente:

  - (void) ccTouchesBegan: (NSSet *) toca conEvent: (UIEvent *) event {UITouch * touch = [toca anyObject];  CGPoint mapLocation = [_tileMap convertTouchToNodeSpace: touch];  Self.tank.shooting = SI;  [Self.tank shootToward: mapLocation];  } - (void) ccTouchesMoved: (NSSet *) toca conEvent: (UIEvent *) event {UITouch * touch = [toca anyObject];  CGPoint mapLocation = [_tileMap convertTouchToNodeSpace: touch];  Self.tank.shooting = SI;  [Self.tank shootToward: mapLocation];  } 

Así que, básicamente, estamos utilizando grifos para disparar ahora en lugar de moverse.

Construir y ejecutar, y ahora se puede tocar la pantalla para desencadenar una granizada de balas! Mwuahaha, el poder!

Cómo hacer un tirador de desplazamiento multidireccional && num; 8211 & semi;  Parte 2

Tenga en cuenta que la forma en que estamos disparando balas aquí realmente no es la mejor porque estamos asignando continuamente las balas, y las asignaciones son caras en iOS. Una mejor manera es preallocar una serie de viñetas y volver a usar viejas viñetas de la matriz cuando se quiere disparar una. Cubrimos cómo hacer esto en el Juego de Starter del Juego Espacial.

Añadiendo algunos enemigos

No podemos tener un juego de tanques sin enemigos para disparar, ¿no?

Así que abre HelloWorldLayer.h y crea una matriz para que podamos seguir la pista de los tanques enemigos en:

  NSMutableArray * _enemyTanks; 

A continuación, abra HelloWorldLayer.m y agregue este código al final de init para crear un montón de tanques:

  _enemyTanks = [matriz NSMutableArray];  Int NUM_ENEMY_TANKS = 50;  Para (int i = 0; i <NUM_ENEMY_TANKS; ++ i) {Tank * enemy = [[Tank alloc] initWithLayer: tipo propio: 2 hp: 2];  CGPoint randSpot;  BOOL inWall = SI;  While (inWall) {randSpot.x = CCRANDOM_0_1 () * [auto tileMapWidth];  RandSpot.y = CCRANDOM_0_1 () * [auto tileMapHeight];  InWall = [self isWallAtPosition: randSpot];  } Enemy.position = randSpot;  [_batchNode addChild: enemigo];  [_enemyTanks addObject: enemigo];  } 

Este código debe ser bastante auto explanitory. Creamos un montón de tanques en lugares aleatorios (siempre y cuando no estén en paredes).

¡Construye y corre, y deberías ver tanques alrededor del mapa! Puesto que tuvimos cuidado de permitir que nuestra clase de tanque para elegir la obra de arte basado en el tipo, que son de diferente color también!

Cómo hacer un tirador de desplazamiento multidireccional && num; 8211 & semi;  Parte 2

Enemigos de Disparos

Por supuesto, están sentados alrededor de no hacer nada, lo que no es divertido! Vamos a agregar alguna lógica básica a estos tanques subclasificando la clase Tank y anulando algunos de los métodos. Vamos a llamar a la clase RandomTank, porque nuestro tanque va a moverse más o menos al azar.

Así que crea un nuevo archivo con la plantilla de clase iOS \ Cocoa Touch \ Objective-C. Nombre de la clase RandomTank y convertirla en una subclase de Tank. Abra RandomTank.h y reemplácelo con lo siguiente:

  #import "Tank.h" @interface RandomTank: Tank {double _timeForNextShot;  }   @fin 

Esto agrega una variable de la instancia que guardamos la pista de cuántos segundos hasta que tiramos después.

Mueva a RandomTank.m y reemplácelo con lo siguiente:

  #import "RandomTank.h" #import "HelloWorldLayer.h" @implementación RandomTank - (id) initWithLayer: (HelloWorldLayer *) tipo de capa: (int) tipo hp: (int) hp {if ((self = [super initWithLayer: Tipo de capa: tipo hp: hp])) {[auto programación: @selector (mover :) intervalo: 0,5];  } Return self;  } - (BOOL) shouldShoot {if (ccpDistance (self.position, _layer.tank.position)> 600) devuelve NO;  If (_timeSinceLastShot> _timeForNextShot) {_timeSinceLastShot = 0;  _timeForNextShot = (CCRANDOM_0_1 () * 3) + 1;  [Self shootToward: _layer.tank.position];  Devolver SI;  } Else {return NO;  }} - (void) calcNextMove {// TODO} - (void) move: (ccTime) dt {if (self.moving && arc4random ()% 3! = 0) return;  [Auto calcNextMove];  }   @fin 

Aquí planificamos un método de movimiento para ser llamado cada medio segundo. Saltando a la implementación, cada vez que llama tiene un 1 en 3 chane para mover el tanque a otra dirección. Vamos a saltar sobre la aplicación de que en este momento y centrarse en el tiroteo sin embargo.

En cuanto al tiroteo, primero verificamos que el tanque enemigo esté lo suficientemente cerca del tanque de héroes. No queremos enemigos lejos disparando a nuestro tanque en este juego, o sería demasiado difícil.

A continuación, averiguar un tiempo aleatorio para el siguiente disparo - en algún lugar entre 1-4 segundos. Si se ha alcanzado ese tiempo, actualizamos el objetivo a donde quiera que esté el tanque y seguimos adelante y disparamos.

Vamos a probar esto! Haga los siguientes cambios en HelloWorldLayer.m:

  // Añadir al principio del archivo #import "RandomTank.h" // Modifica la línea en init para crear un RandomTank en lugar de un tanque normal RandomTank * enemy = [[RandomTank alloc] initWithLayer: self type: 2 hp: 2]; 

¡Eso es! ¡Compila y corre, y ahora los tanques te dispararán cuando te acerques!

Cómo hacer un tirador de desplazamiento multidireccional && num; 8211 & semi;  Parte 2

Moviendo enemigos

Hasta ahora nuestros enemigos están disparando, pero no hemos terminado de hacer que se muevan.

Para mantener las cosas simples para este juego, la estrategia que queremos tomar es:

  1. Elija un lugar aleatorio cercano.
  2. Asegúrese de que hay un camino claro hacia ese lugar. Si es así, ¡adelante!
  3. De lo contrario, vuelva al paso 1.

La única cosa difícil es "asegurarse de que hay un camino claro a ese punto." Dada una coordenada de inicio y fin de la baldosa, ¿cómo podemos caminar a través de todas las baldosas que el tanque se movería entre y asegurarse de que están todos claros?

Por suerte, este es un problema resuelto, y James McNeill tiene un excelente post en el blog sobre el tema. Sólo tomaremos su implementación y la conectaremos.

Vuelva a RandomTank.m y reemplace el método calcNextMove con lo siguiente:

  // De http://playtechs.blogspot.com/2007/03/raytracing-on-grid.html - (BOOL) clearPathFromTileCoord: (CGPoint) comienza toTileCoord: (CGPoint) end {int dx = abs (end.x - Start.x);  Int dy = abs (end.y - start.y);  Int x = start.x;  Int y = start.y;  Int n = 1 + dx + dy;  Int x_inc = (end.x> start.x)?  1: 1;  Int y_inc = (end.y> start.y)?  1: 1;  Int error = dx - dy;  Dx * = 2;  Dy * = 2;  Para (; n> 0; --n) {if ([_layer isWallAtTileCoord: ccp (x, y)]) devuelve FALSE;  If (error> 0) {x + = x_inc;  Error - = dy;  } Else {y + = y_inc;  Error + = dx;  }} Return TRUE;  } - (void) calcNextMove {BOOL moveOK = NO;  CGPoint start = [_layer tileCoordForPosition: self.position];  CGPoint end;  Mientras que (! MoveOK) {end = start;  End.x + = CCRANDOM_MINUS1_1 () * ((arc4random ()% 10) + 3);  End.y + = CCRANDOM_MINUS1_1 () * ((arc4random ()% 10) + 3);  MoveOK = [auto clearPathFromTileCoord: start toTileCoord: end];  } CGPoint moveToward = [_layer positionForTileCoord: end];  Self.moving = SI;  [Movimiento de sí mismoTola: moveToward];  } 

No te preocupes por cómo funciona el primer método (aunque puedes leer la entrada en el blog si tienes curiosidad) - sólo sé que comprueba si hay una pared en cualquier coordenada entre las coordenadas de inicio y fin del mosaico y devuelve FALSO si es así.

En calcNextMove, seguimos nuestro algoritmo como se ha descrito anteriormente. Bastante straigtforward eh?

Eso es todo - construir y ejecutar, y ahora tienes enemigos en movimiento!

Colisiones, Explosiones y Salidas

Ahora que tenemos enemigos para disparar y balas para esquivar, sé lo que ustedes quieren ... toneladas de explosiones, y una manera de ganar el juego!

Me alegro de obligar. Realice los cambios siguientes en HelloWorldLayer.h:

  // Añadir antes de @interface typedef enum {kEndReasonWin, kEndReasonLose} EndReason;  // Añadir dentro de @interface CCParticleSystemQuad * _explosion;  CCParticleSystemQuad * _explosion2;  BOOL _gameOver;  CCSprite * _exit; 

A continuación, cambie a HelloWorldLayer.m y agregue esto a la parte inferior de init:

  _explosion = [CCParticleSystemQuad particleWithFile: @ "explosion.plist"];  [_explosion stopSystem];  [_tileMap addChild: _explosion z: 1];  _explosion2 = [CCParticleSystemQuad particleWithFile: @ "explosion2.plist"];  [_explosion2 stopSystem];  [_tileMap addChild: _explosion2 z: 1];  _exit = [CCSprite spriteWithSpriteFrameName: @ "exit.png"];  CGPoint exitTileCoord = ccp (98, 98);  CGPoint exitTilePos = [posición de uno mismoTablaDeForma: exitTileCoord];  _exit.position = exitTilePos;  [_batchNode addChild: _exit];  Escala de auto = 0,5; 

Aquí creamos los dos tipos de explosiones que usaremos y los agregamos al mapa de azulejos, pero asegúrese de que estén apagados. Cuando queremos usarlos, los trasladaremos a donde debemos ejecutarlos e iniciarlos con resetSystem.

También añadimos una salida a la esquina inferior derecha del mapa. Una vez que el tanque llega a este lugar, usted gana!

Por último, nota que establecer la escala de la capa a 0,5 porque este juego funciona mucho mejor cuando se puede ver más del mapa a la vez.

A continuación, agregue estos nuevos métodos justo antes de la actualización:

  - (void) restartTapped: (id) remitente {[[CCDirector sharedDirector] replaceScene: [CCTransitionZoomFlipX transitionWithDuration: 0.5 escena: [escena HelloWorldLayer]]];  } - (void) endScene: (EndReason) endReason {if (_gameOver) return;  _gameOver = true;  CGSize winSize = [CCDirector sharedDirector] .winSize;  NSString * mensaje;  If (endReason == kEndReasonWin) {message = @ "¡Usted gana!";  } Else if (endReason == kEndReasonLose) {message = @ "¡Pierdes!";  } CCLabelBMFont * etiqueta;  If (UI_USER_INTERFACE_IDIOM () == UIUserInterfaceIdiomPad) {label = [CCLabelBMFont labelWithString: mensaje fntFile: @ "TanksFont.fnt"];  } Else {label = [CCLabelBMFont labelWithString: mensaje fntFile: @ "TanksFont.fnt"];  } Label.scale = 0.1;  Label.position = ccp (winSize.width / 2, winSize.height * 0.7);  [Self addChild: etiqueta];  CCLabelBMFont * restartLabel;  If (UI_USER_INTERFACE_IDIOM () == UIUserInterfaceIdiomPad) {restartLabel = [CCLabelBMFont labelWithString: @ "Reiniciar" fntFile: @ "TanksFont.fnt"];  } Else {restartLabel = [CCLabelBMFont labelWithString: @ "Reiniciar" fntFile: @ "TanksFont.fnt"];  } CCMenuItemLabel * restartItem = [CCMenuItemLabel itemWithLabel: restartLabel target: auto selector: @selector (restartTapped :)];  RestartItem.scale = 0,1;  RestartItem.position = ccp (winSize.width / 2, winSize.height * 0.3);  CCMenu * menu = [CCMenu menuWithItems: restartItem, nil];  Menu.position = CGPointZero;  [Self addChild: menú];  [RestartItem runAction: [CCScaleTo actionWithDuration: 0.5 scale: 4.0]];  [Label runAction: [CCScaleTo actionWithDuration: 0.5 scale: 4.0]];  } 

Estos son mis prácticos métodos de "juego más" que utilizo muy a menudo cuando se prototiplan juegos. Los más dedicados lectores de tutoriales entre ustedes pueden recordar este método de varios otros tutoriales;] De todos modos lo usaremos para reiniciar el juego, y no lo cubriremos en detalle aquí ya que es algo bastante simple.

A continuación, agregue este código al principio de la actualización:

  // 1 si (_gameOver) devuelve;  // 2 if (CGRectIntersectsRect (_exit.boundingBox, _tank.boundingBox)) {[auto endScene: kEndReasonWin];  } // 3 NSMutableArray * childrenToRemove = [matriz NSMutableArray];  // 4 for (CCSprite * sprite en self.batchNode.children) {// 5 if (sprite.tag! = 0) {// bullet // 6 si ([self isWallAtPosition: sprite.position]) {[childrenToRemove addObject :duende];  continuar;  } // 7 if (sprite.tag == 1) {// héroe bullet para (int j = _enemyTanks.count - 1; j> = 0; j--) {Tank * enemy = [_enemyTanks objectAtIndex: j];  If (CGRectIntersectsRect (sprite.boundingBox, enemy.boundingBox)) {[childrenToRemove addObject: sprite];  Enemy.hp--;  If (enemy.hp <= 0) {[[SimpleAudioEngine sharedEngine] playEffect: @ "explode3.wav"];  _explosion.position = enemy.position;  [_explosion resetSystem];  [_enemyTanks removeObject: enemigo];  [ChildrenToRemove addObject: enemigo];  } Else {[[SimpleAudioEngine sharedEngine] playEffect: @ "explode2.wav"];  }}}} // 8 if (sprite.tag == 2) {// bullet enemigo si (CGRectIntersectsRect (sprite.boundingBox, self.tank.boundingBox)) {[childrenToRemove addObject: sprite];  Self.tank.hp-;  If (self.tank.hp <= 0) {[[SimpleAudioEngine sharedEngine] playEffect: @ "explode2.wav"];  _explosion.position = self.tank.position;  [_explosion resetSystem];  [Self endScene: kEndReasonLose];  } Else {_explosion2.position = self.tank.position;  [_explosion2 resetSystem];  [[SimpleAudioEngine sharedEngine] playEffect: @ "explode1.wav"];  }}}}} Para (CCSprite * child en childrenToRemove) {[child removeFromParentAndCleanup: YES];  } 

Esta es nuestra detección de colisión y lógica de juego. Vamos a caminar a través de ella poco a poco.

  1. Estamos empezando a hacer un seguimiento de si el juego ha terminado, y no hay necesidad de hacer nada de esto si el juego ha terminado. Esto se establece cuando llamamos al método endScene que acabamos de agregar.
  2. Si el tanque cruza la salida, el jugador gana!
  3. Estamos a punto de empezar a buscar colisiones ya veces cuando las cosas chocan, un sprite puede ser removido de la escena (por ejemplo, si una bala cruza con un tanque o una pared, la bala se eliminará). Sin embargo, puesto que estamos iterando a través de la lista de los niños, no podemos modificar la lista mientras la estamos iterando. Así que simplemente agregamos lo que queremos quitar a una matriz, y eliminarlo cuando hayamos terminado.
  4. Establecimos una etiqueta en sprites de bala para que pudiéramos identificarlos fácilmente - igual al tipo de tanque que lo disparó (1 o 2). No tenemos una etiqueta en ninguna otra cosa, así que si hay una etiqueta sabemos que es una bala.
  5. Si hay un muro donde está la bala, quite la bala.
  6. Si es una bala el héroe disparó, compruebe para ver si golpeó cualquier tanque enamy. Si lo hace, reduzca el HP enemigo (y destruirlo si está muerto). También jugar algunos efectos de sonido de explosión gratuita y, posiblemente, un sistema de partículas de explosión!
  7. Del mismo modo, si se trata de una bala enemiga verifique si se ha golpeado el jugador y reaccionar adecuadamente. Juego encima si el jugador alcanza 0 HP.

Como último paso, ponga esto al principio del acelerómetro: didAccelerate, ccTouchesBegan y ccTouchesMoved:

  If (_gameOver) return; 

Construir y ejecutar, y ver si se puede superar el juego - y no justo hacking el código para ganar! ;]

Cómo hacer un tirador de desplazamiento multidireccional && num; 8211 & semi;  Parte 2

El reto final

Como un reto final para este proyecto, ¿por qué no intenta agregar una capa de HUD a este proyecto usted mismo? Aquí están las especificaciones:

  • Debe haber una línea que muestre su número actual de vidas.
  • Debe haber una línea que dice "Salir" con una flecha al lado. La flecha debe apuntar en la dirección de la salida, relativa al tanque.

Esto debería ser una buena revisión de trabajar con múltiples capas, pasar datos entre capas y trabajar con algunas funciones matemáticas vectoriales. Si te quedas atascado, quizás quieras revisar el tutorial de cómo crear un HUD Layer con Cocos2D ... o siempre puedes engañar mirando la solución al final del artículo;]

Feliz hacking!

¿A dónde ir desde aquí?

Aquí hay un proyecto de ejemplo con todo el código de la serie tutorial anterior (incluyendo el desafío opcional de HUD).

¡En este punto, usted tiene los fundamentos de un juego bastante divertido! ¡Siéntete libre de agregar funciones adicionales, cambiar las ilustraciones y usarlas como base para una aplicación propia!

Si tiene alguna pregunta o comentario sobre este tutorial, por favor, únase a la discusión del foro a continuación.

Etiqueta:

Artículos relacionados

Popular

Último