Sprite Kit es una de las nuevas tecnologías más emocionantes disponibles con el iOS 7 SDK y Xcode 5, pero ¿cómo se compara con un motor de juego establecido como Cocos2D? Este tutorial proporcionará una breve introducción a Sprite Kit antes de echar un vistazo completo a cómo se compara con Cocos2D.
De todos los juegos disponibles en la App Store, muchos de los más descargados y más rentables son los juegos en 2D. Algunos títulos icónicos en esta categoría incluyen Angry Birds, Tiny Wings y Cut the Rope. La conducción del éxito de estos juegos tiene varias características comunes: hermosos gráficos, efectos de partículas, un motor de física, una animación perfecta y efectos de sonido convincentes.
Antes del lanzamiento del iOS 7 SDK, la creación de juegos como estos solo era posible con el uso de marcos y motores de terceros. Ahora, con la introducción de Sprite Kit, los desarrolladores no necesitan buscar más que el SDK nativo para encontrar todo lo que necesitan para poder construir excelentes juegos 2D y 2.5D. La funcionalidad provista por Sprite Kit incluye Sprites, Formas, Partículas (por ejemplo, fuego, humo, etc.), Animaciones, Simulación de Física, Audio, Video y Efectos Visuales. Xcode 5 ahora también proporciona soporte para paquetes de textura y diseño de partículas..
El kit de Sprite puede resumirse lógicamente en las siguientes tres partes:
Apple cuenta con una plataforma de juegos 2D y 2.5D que mantiene y mantiene algunos beneficios muy sólidos. Considere los siguientes puntos:
El desarrollo nativo y las herramientas nativas tienen que ver con el rendimiento.
A pesar del hecho de que los desarrolladores suelen querer que sus juegos se ejecuten en tantas plataformas diferentes como sea posible, un juego nativo casi siempre tendrá un mejor rendimiento que un juego no nativo. Además, si las herramientas para desarrollar esos juegos son nativas, uno puede asegurarse de que el código esté integrado con el ecosistema de la plataforma.
Como se mencionó anteriormente, Sprite Kit y Xcode 5 combinan muchos de los componentes esenciales para crear excelentes juegos. Esto significa que el desarrollo puede ser más ágil y que las herramientas serán más confiables y efectivas..
Escribir un juego usando un framework de terceros o un motor de juego es siempre una espada de dos filos. Nunca sabemos si las herramientas serán compatibles con futuras actualizaciones de la plataforma, o incluso si el juego funcionará bien después de una actualización. Cuando las cosas se rompen, no se sabe cuánto tiempo tomará la comunidad para solucionar los errores.
Cocos2D es un ejemplo de un proyecto de código abierto que debe resolver este problema. El código está en constante evolución, y en cada nueva versión se deben realizar varios pasos de seguridad para garantizar que las aplicaciones creadas con Cocos2D se ejecutarán en la versión más reciente de iOS y el último hardware..
Con Sprite Kit, Apple ha proporcionado un conjunto de herramientas para garantizar que el código del juego funcione en todos los dispositivos compatibles sin ningún problema. Tenga en cuenta que Sprite Kit no es solo un framework iOS. Los desarrolladores también pueden comenzar a crear juegos Sprite Kit para OS X, y es una apuesta segura que los juegos Sprite Kit también se ejecutarán en cualquier dispositivo iOS futuro..
La facilidad de uso fue un factor importante detrás del éxito de los motores de juegos como Cocos2D. En general, a los desarrolladores les resultó mucho más fácil implementar Cocos2D que otras alternativas nativas como OpenGL ES. Con Cocos2D, todas las llamadas de API de bajo nivel se transformaron en métodos simples.
Sprite Kit sigue este enfoque y ofrece cientos de métodos que facilitan mucho el proceso de desarrollo del juego. El kit Sprite es amigable también. Tiene la API de Apple personalizada y bien diseñada y viene con una documentación estructurada completa. Apple ha hecho un trabajo excelente de afilar esta herramienta para que la utilicen los desarrolladores de terceros. La mayor ventaja de todas es que viene completamente cargado con todos los recursos que necesitas para crear un juego. Física, efectos de sonido, efectos de partículas, texturas, gestión de escenas: todo está incluido en un solo paquete.
Tenga en cuenta que, en la presentación inicial de Sprite Kit, Ricardo Quesada, El desarrollador líder de Cocos2D. dijo lo siguiente en Twitter:
El kit de Sprite es muy bueno. Con menos características que Cocos2D, pero mejor. Me gusta la integracion fisica.
Este es un gran elogio proveniente de una de las mentes líderes detrás de Cocos2D!
Característica | Kit de Sprite | Cocos2D |
Fuente abierta | No | Sí |
Soporte nativo de Objective-C | Sí | Sí |
Motor grafico | Sí | Sí |
Animaciones | Sí | Sí |
Simulación de física | Si (integrado) | No (requiere Box2D o Ardilla) |
Efectos de partículas | Sí | Sí |
Integración Xcode Native | Sí | No |
Creación automática de atlas | Sí | No |
Editor de partículas incorporado | Sí | No |
Sombreadores | No | Sí |
Cámara | No | Sí |
Entonces, ¿qué aspecto tienen los proyectos con cada motor de juego? Para responder a esta pregunta, los autores han incluido el código fuente completo para un kit de Sprite y un proyecto de Cocos2D. Puedes usar estos proyectos como una comparación de alto nivel de cada motor de juego..
En esta sección, realmente desglosaremos las tareas y los conceptos comunes, mostrando cómo implementarlos tanto en Cocos2D como en Sprite Kit..
CCLayer o SkScene es el objeto principal utilizado para dibujar otros objetos. Puede considerar esto como la vista predeterminada que recibirá todos los objetos, animaciones y eventos táctiles..
La transición entre escenas en Cocos2D se realiza con los siguientes pasos:
GameScene * gameScene = [[GameScene alloc] init]; [[CCDirector sharedDirector] replaceScene: gameScene];
Tenga en cuenta que el GameScene.h
archivo debe ser de la CCLayer
categoría y tener el inicializador específico disponible.
@interface GameScene: escena de CCLayer + (CCScene *);
En GameScene.m
, La implementación inicial es:
+(CCScene *) escena CCScene * escena = [nodo CCScene]; GameScene * layer = [nodo GameScene]; [escena addChild: capa]; escena de retorno - (id) init if ((self = [super init])) // Tu código aquí devuelve self;
En Sprite Kit la transición es similar:
GameScene * gameScene = [[GameScene alloc] initWithSize: CGSizeMake (1024, 768)]; [self.scene.view presentScene: gameScene];
los GameScene
debe ser del SKScene
categoría, y la -(id) initWithSize: (CGSize) tamaño
es el inicializador personalizado. Un ejemplo simple:
-(id) initWithSize: (CGSize) tamaño if (self = [super initWithSize: size]) // Su código devuelve self;
Los objetos Sprite se utilizan normalmente para mostrar algún tipo de imagen. Puede tener varias propiedades, tales como: rotación, escala, posición, marcos, identificadores y más. La implementación de Cocos2D y Sprite Kit son similares. La implementación de Cocos2D es:
CCSprite * aSprite; aSprite = [CCSprite spriteWithFile: @ "player.png"]; aSprite.scale = .5; aSprite.position = ccp (_size.width / 1.30, _size.height / 1.25); [auto addChild: aSprite];
Mientras que en Sprite Kit la implementación es:
SKSpriteNode * planeShadow = [SKSpriteNode spriteNodeWithImageNamed: @ "player.png"]; planeShadow.scale = 0.5; planeShadow.position = CGPointMake (CGRectGetMidX (self.frame) + 100, CGRectGetMidY (self.frame) +200); [auto addChild: planeShadow];
Los objetos de etiqueta se utilizan para mostrar texto. Puede tener varias propiedades, incluyendo texto, tamaño del texto, color del texto, posición y muchas otras. La implementación de Cocos2D y Sprite Kit son similares. La implementación de Cocos2D es:
CCLabelTTF * label = [CCLabelTTF labelWithString: @ "Hello World" fontName: @ "Marker Felt" fontSize: 64]; // pregunte al director el tamaño de la ventana CGSize size = [[CCDirector sharedDirector] winSize]; label.position = ccp (size.width / 2, size.height / 2); [auto addChild: etiqueta];
La implementación del kit Sprite es:
SKLabelNode * gameScene = [SKLabelNode labelNodeWithFontNamed: @ "Chalkduster"]; [gameScene setText: @ "New Game"]; [gameScene setFontSize: 18]; gameScene setPosition: CGPointMake (CGRectGetMidX (self.frame) + 5, CGRectGetMidY (self.frame) -40)]; [auto addChild: gameScene];
En Cocos2D, los menús se crean utilizando dos objetos: CCMenu
y CCMenuItem
. El siguiente ejemplo presenta un menú con 2 opciones en Cocos2D:
CGSize size = [[CCDirector sharedDirector] winSize]; [CCMenuItemFont setFontSize: 28]; CCMenuItem * itemNewGame = [CCMenuItemFont itemWithString: @ bloque "Nuevo juego": ^ (remitente de identificación) // Tu código]; CCMenuItem * itemOptions = [CCMenuItemFont itemWithString: @ bloque "Opciones": ^ (remitente de identificación) NSLog (@ "Segundo elemento"); ]; CCMenu * menu = [CCMenu menuWithItems: itemNewGame, itemOptions, nil]; [menú alignItemsHorizontallyWithPadding: 20]; [menu setPosition: ccp (size.width / 2, size.height / 2 - 50)]; [auto addChild: menu];
SpiteKit no incluye ningún tipo de objeto específico de menú. Debe crear un controlador de eventos para un objeto específico con el fin de activarlo para la entrada del usuario. Entonces, para "crear" un menú debe usar un objeto UIKit o un objeto Sprite Kit.
El siguiente ejemplo usa un SKLabelNode
como un elemento del menú. Primero, definimos la SKLabelNode
:
SKLabelNode * gameScene = [SKLabelNode labelNodeWithFontNamed: @ "Chalkduster"]; [gameScene setText: @ "New Game"]; [gameScene setFontSize: 18]; [gameScene setPosition: CGPointMake (CGRectGetMidX (self.frame) + 5, CGRectGetMidY (selfframe) -40)]; [auto addChild: gameScene];
Dentro de -(void) touchesBegan: (NSSet *) toca conEvent: (UIEvent *) event
Método, crearemos el controlador de eventos que interceptará el evento táctil:
para (UITouch * touch in touches) CGPoint location = [touch locationInNode: self]; if ([gameScene includesPoint: location]) // Animación de transición de escena SKTransition * reveal = [SKTransition revealWithDirection: SKTransitionDirectionDown duration: 1]; GameScene * gameScene = [[GameScene alloc] initWithSize: CGSizeMake (1024, 768)]; [self.scene.view presentScene: gameScene transición: revelar]; NSLog (@ "Touched gameScene !!!!");
El código mencionado hace varias cosas:
SKLabelNode
objeto.La principal diferencia entre Action y SKAction es que SKAction es un objeto complejo con varias propiedades. La acción en Cocos2D es solo una acción que el programador debe definir, llamar y tratar.
Con Sprite Kit, SKAction ofrece varias opciones para los desarrolladores, como rotación, cambio de tamaño, escala, repetición, atenuación, reproducción de sonido y más. SKaction se puede ver como un objeto abstracto que se ocupa de cualquier tipo de acción, desde el sonido hasta los sprites y los nodos..
Nos centraremos por el momento en acciones de movimiento..
En Cocos2D necesitamos definir un planificador para llamar a un método personalizado:
[programación propia: @selector (addSprite :) intervalo: 1];
Y luego define el método personalizado para hacer la animación personalizada..
- (void) addSprite: (ccTime) dt CCSprite * aMovableSprite = [CCSprite spriteWithFile: @ "frankenstein.png"]; aMovableSprite.scale = .8; [auto addChild: aMovableSprite]; CGSize winSize = [CCDirector sharedDirector] .winSize; int minX = aMovableSprite.contentSize.width / 2; int maxX = winSize.width - aMovableSprite.contentSize.width / 2; int rangeX = maxX - minX; int actualY = (arc4random ()% rangeX) + minX; CCCallBlockN * actionMoveDone = [CCCallBlockN actionWithBlock: ^ (nodo CCNode *) NSLog (@ "Sprite free!"); ]; NSMutableArray * arrayBezier = [[NSMutableArray alloc] init]; ccBezierConfig bezier; id bezierAction1; float splitDuration = 6 / 6.0; para (int i = 0; i< 6; i++) if(i % 2 == 0) bezier.controlPoint_1 = ccp(actualY+100,winSize.height-(100+(i*200))); bezier.controlPoint_2 = ccp(actualY+100,winSize.height-(100+(i*200))); bezier.endPosition = ccp(actualY,winSize.height-(200+(i*200))); bezierAction1 = [CCBezierTo actionWithDuration:splitDuration bezier:bezier]; else bezier.controlPoint_1 = ccp(actualY-100,winSize.height-(100+(i*200))); bezier.controlPoint_2 = ccp(actualY-100,winSize.height-(100+(i*200))); bezier.endPosition = ccp(actualY,winSize.height-(200+(i*200))); bezierAction1 = [CCBezierTo actionWithDuration:splitDuration bezier:bezier]; [arrayBezier addObject:bezierAction1]; [arrayBezier addObject:actionMoveDone]; id seq = [CCSequence actionsWithArray:arrayBezier]; [aMovableSprite runAction:seq];
En Sprite Kit, podemos usar SKAction para controlar lo que le sucede a un objeto al principio y al final del movimiento. Las siguientes líneas muestran cómo mover cualquier objeto en línea recta:
SKSpriteNode * playerSprite = [SKSpriteNode spriteNodeWithImageNamed: @ "player.png"]; [playerSprite setScale: 0.4]; SKAction * movement = [SKAction moveTo: CGPointMake (900, 500) duración: 5]; SKAction * remove = [SKAction removeFromParent]; [playerSprite runAction: [Secuencia de SKAction: @ [movimiento, eliminar]]]; [auto addChild: playerSprite];
Sin embargo, podemos definir una acción personalizada y usar SKAction para activar esa acción. El siguiente ejemplo ejemplifica un movimiento Bézier (similar a la versión de Cocos2D de Action). Tenga en cuenta que debemos definir un planificador para llamar a un método personalizado.
SKAction * wait = [SKAction waitForDuration: 1]; SKAction * callEnemies = [SKAction runBlock: ^ [self sendNewSKSpriteNode]; ]; SKAction * updateSKSpriteNodeOnScreen = [secuencia SKAction: @ [wait, callEnemies]]; [self runAction: [SKAction repeatActionForever: updateSKSpriteNodeOnScreen]];
El método enviarNewsSKSpriteNode
Manejará el movimiento de objetos personalizados..
-(void) sendNewSKSpriteNode CGRect screenRect = [[UIScreen mainScreen] lines]; // SKAction personalizado SKSpriteNode * enemy = [SKSpriteNode spriteNodeWithImageNamed: @ "frankenstein.png"]; enemigo.escala = 0.6; CGMutablePathRef cgpath = CGPathCreateMutable (); // los valores aleatorios flotan xStart = [self getRandomNumberBetween: 0 + enemy.size.width a: screenRect.size.width-enemy.size.width]; float xEnd = [self getRandomNumberBetween: 0 + enemy.size.width to: screenRect.size.width-enemy.size.width]; // ControlPoint1 float cp1X = [self getRandomNumberBetween: 0 + enemy.size.width to: screenRect.size.width-enemy.size.width]; float cp1Y = [self getRandomNumberBetween: 0 + enemy.size.width to: screenRect.size.width-enemy.size.height]; // ControlPoint2 float cp2X = [self getRandomNumberBetween: 0 + enemy.size.width to: screenRect.size.width-enemy.size.width]; float cp2Y = [self getRandomNumberBetween: 0 to: cp1Y]; CGPoint s = CGPointMake (xStart, 1024.0); CGPoint e = CGPointMake (xEnd, -100.0); CGPoint cp1 = CGPointMake (cp1X, cp1Y); CGPoint cp2 = CGPointMake (cp2X, cp2Y); CGPathMoveToPoint (cgpath, NULL, s.x, s.y); CGPathAddCurveToPoint (cgpath, NULL, cp1.x, cp1.y, cp2.x, cp2.y, e.x, e.y); SKAction * planeDestroy = [SKAction followPath: cgpath asOffset: NO orientToPath: YES duration: 5]; [auto addChild: enemigo]; SKAction * remove2 = [SKAction removeFromParent]; [runAction enemigo: [Secuencia de SKAction: @ [planeDestroy, remove2]]]; CGPathRelease (cgpath);
Cocos2D no tiene ningún tipo de editor de partículas. Uno debe usar una aplicación externa para crear la partícula y luego usar específica CCPartículaExplosión
Propiedades para cambiar su comportamiento. Una vez que tenga la partícula en su proyecto Xcode, puede llamarla usando:
CCParticleExplosion * _particleExplosion; particleExplosion = [[CCParticleExplosion alloc] initWithTotalParticles: 800]; particleExplosion.texture = [[CCTextureCache sharedTextureCache] addImage: @ "texture.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 = ccp (_size.width / 5, _size.height / 5); [Sistema de restablecimiento de partículas de explosión];
Los emisores se utilizan dentro del kit Sprite para la generación de partículas. Para usarlos, necesita agregar una partícula a su proyecto. Ir Nuevo -> Archivo -> Recurso -> Archivo de partículas de Sprite Kit
. A continuación, debe nombrarlo y elegir cualquier tipo de partícula (fuego, magia, humo, nieve, entre otros). Ahora verá que aparecerán dos nuevos archivos en su proyecto Xcode. Los implementarás con:
SKEmitterNode * smokeTrail; NSString * smokePath = [[NSBundle mainBundle] pathForResource: @ "MyParticle" ofType: @ "sks"]; smokeTrail = [NSKeyedUnarchiver unarchiveObjectWithFile: smokePath]; smokeTrail.position = CGPointMake (CGRectGetMidX (self.frame) + 40, CGRectGetMidY (self.frame) -100); [auto addChild: smokeTrail];
La clase SKEmitterNode es extensa y contiene varias propiedades. Le recomendamos que lo lea para conocer todas las propiedades que puede tener un nodo emisor..
El sonido es una parte activa de cualquier juego o aplicación multimedia. En Cocos2D, podemos lograr eso con dos pasos. El primero es incluir el SimpleAudioEngine
archivo de cabecera.
#import "SimpleAudioEngine.h"
Luego usa las siguientes líneas para llamar al archivo de música dentro de nuestro proyecto:
[[SimpleAudioEngine sharedEngine] playBackgroundMusic: @ "sound.caf" loop: YES]; [[SimpleAudioEngine sharedEngine] setEffectsVolume: 0.4f];
A veces, Xcode no incluye automáticamente el archivo de música en "Copiar los recursos del paquete". Si eso sucede debes agregarlo manualmente..
Con Sprite Kit, las inclusiones de los sonidos son sencillas:
SKAction * soundAction = [SKAction playSoundFileNamed: @ "preview.mp3" waitForCompletion: NO]; [self runAction: soundAction];
Tenga en cuenta que para lograr esto con Sprite Kit, una vez más usó el objeto SKAction.
Como puede ver en el análisis anterior, Cocos2D y Sprite Kit tienen muchas similitudes. Cocos2D usa varias capas para cada objeto, mientras que Sprite Kit encapsula más objetos y usa la súper clase NSObject para lograr ciertos objetivos (como botones o menús).
En términos de facilidad de uso, Sprite Kit realmente brilla cuando desea utilizar el sistema de partículas o el ejecutante de acción. Sin embargo, cuando se trabaja con objetos más generales, ambos marcos tienen el mismo nivel de dificultad..
No obstante, la creación de un juego con Sprite Kit trae muchos beneficios clave, como un motor de física totalmente integrado, herramientas de flujo de trabajo optimizadas en Xcode 5, compatibilidad con iOS y OS X, y mantenimiento oficial por parte de Apple..
La pregunta es: ¿cuál usarás para tu próximo proyecto de juego 2D? Háganos saber en los comentarios..