Sprite Kit è una delle nuove tecnologie più interessanti disponibili con iOS 7 SDK e Xcode 5, ma come si confronta con un motore di gioco affermato come Cocos2D? Questo tutorial fornirà una breve introduzione a Sprite Kit prima di dare uno sguardo completo su come si sovrappone a Cocos2D.
Di tutti i giochi disponibili su App Store, molti dei giochi 2D più scaricati e più redditizi. Alcuni titoli iconici in questa categoria includono Angry Birds, Tiny Wings e Cut the Rope. A guidare il successo di questi giochi ci sono diverse caratteristiche comuni: una grafica stupenda, effetti particellari, un motore fisico, animazioni fluide e effetti sonori avvincenti.
Prima del rilascio di iOS 7 SDK, la costruzione di giochi come questi era possibile solo con l'uso di framework e motori di terze parti. Ora, con l'introduzione di Sprite Kit, gli sviluppatori non devono guardare oltre l'SDK nativo per trovare tutto ciò di cui hanno bisogno per essere in grado di creare grandi giochi 2D e 2.5D. La funzionalità fornita da Sprite Kit include sprite, forme, particelle (ad esempio fuoco, fumo, ecc.), Animazioni, simulazione fisica, audio, video ed effetti visivi. Xcode 5 ora fornisce anche supporto per pacchetti texture e progettazione di particelle.
Sprite Kit può essere logicamente estratto nelle seguenti tre parti:
Ci sono alcuni vantaggi molto solidi nell'avere una piattaforma di gioco 2D e 2.5D fornita e gestita da Apple. Considera i seguenti punti:
Lo sviluppo nativo e gli strumenti nativi riguardano esclusivamente le prestazioni.
Nonostante gli sviluppatori in genere desiderino che i loro giochi funzionino su quante più piattaforme possibili, un gioco nativo avrà quasi sempre prestazioni migliori rispetto a un gioco non nativo. Inoltre, se gli strumenti per sviluppare quei giochi sono nativi, è possibile garantire che il codice sia integrato con l'ecosistema della piattaforma.
Come accennato in precedenza, Sprite Kit e Xcode 5 combinano molti dei componenti essenziali per creare giochi fantastici. Ciò significa che lo sviluppo può essere semplificato e gli strumenti saranno più affidabili ed efficaci.
Scrivere un gioco usando un framework di terze parti o un motore di gioco è sempre un'arma a doppio taglio. Non sappiamo mai se gli strumenti saranno compatibili con i futuri aggiornamenti della piattaforma, o anche se il gioco funzionerà bene dopo un aggiornamento. Quando le cose si rompono, non è sicuro quanto tempo ci vorrà perché la comunità risolva i bug.
Cocos2D è un esempio di un progetto open source che deve affrontare questo problema. Il codice è in continua evoluzione e ad ogni nuova versione è necessario eseguire diversi passaggi di sicurezza per garantire che le applicazioni create con Cocos2D continuino a funzionare sulla versione più recente di iOS e sull'hardware più recente.
Con Sprite Kit, Apple ha fornito una serie di strumenti per garantire che il codice di gioco funzioni su tutti i dispositivi compatibili senza alcun problema. Nota che Sprite Kit non è solo un framework iOS. Gli sviluppatori possono iniziare a creare giochi Sprite Kit anche per OS X, ed è una scommessa sicura che i giochi Sprite Kit funzioneranno su qualsiasi futuro dispositivo iOS.
La facilità d'uso è stata uno dei fattori principali del successo dei motori di gioco come Cocos2D. In generale, gli sviluppatori hanno trovato Cocos2D molto più facile da implementare rispetto ad altre alternative native come OpenGL ES. Con Cocos2D, tutte le chiamate API di basso livello sono state trasformate in metodi semplici.
Sprite Kit segue questo approccio e offre centinaia di metodi che rendono il processo di sviluppo del gioco molto più semplice. Sprite Kit è amichevole pure. Ha l'API Apple personalizzata e ben progettata e viene fornita con una documentazione strutturata completa. Apple ha fatto un lavoro eccezionale per perfezionare questo strumento per i dispositivi di sviluppo di terze parti da utilizzare. Il più grande vantaggio di tutti è che viene completamente caricato con tutte le risorse necessarie per creare un gioco. Fisica, effetti sonori, effetti particellari, trame, gestione delle scene: tutto è incluso in un unico pacchetto.
Si noti che, alla presentazione iniziale di Sprite Kit, Ricardo Quesada, lo sviluppatore principale di Cocos2D ha detto quanto segue su Twitter:
Sprite Kit è molto buono. Con meno funzioni di Cocos2D, ma migliore. Mi piace l'integrazione fisica.
Questo è un grande elogio proveniente da una delle menti principali di Cocos2D!
caratteristica | Kit Sprite | cocos2d |
Open Source | No | sì |
Supporto nativo Objective-C | sì | sì |
Motore grafico | sì | sì |
animazioni | sì | sì |
Simulazione fisica | Sì (integrato) | No (Richiede Box2D o Chipmunk) |
Effetti particellari | sì | sì |
Xcode Native Integration | sì | No |
Creazione automatica dell'atlante | sì | No |
Editor di particelle integrato | sì | No |
shaders | No | sì |
telecamera | No | sì |
Quindi, che aspetto hanno effettivamente i progetti con ciascun motore di gioco? Per rispondere a questa domanda, gli autori hanno incluso il codice sorgente completo sia per un Sprite Kit che per un progetto Cocos2D. Puoi utilizzare questi progetti come confronto ad alto livello di ciascun motore di gioco.
In questa sezione analizzeremo in realtà compiti e concetti comuni, mostrando come implementarli sia in Cocos2D che in Sprite Kit.
CCLayer o SkScene è l'oggetto principale utilizzato per disegnare altri oggetti. Puoi pensare a questo come alla vista predefinita che riceverà tutti gli oggetti, le animazioni e gli eventi di tocco.
La transizione tra le scene in Cocos2D viene eseguita con i seguenti passaggi:
GameScene * gameScene = [[GameScene alloc] init]; [[CCDirector sharedDirector] replaceScene: gameScene];
Si noti che il GameScene.h
il file deve essere del CCLayer
categoria e hanno l'inizializzatore specifico disponibile.
@interface GameScene: CCLayer + (CCScene *) scena;
Nel GameScene.m
, l'implementazione iniziale è:
+(CCScene *) scene CCScene * scene = [nodo CCScene]; GameScene * layer = [nodo GameScene]; [scene addChild: layer]; scena di ritorno; - (id) init if ((self = [super init])) // Il tuo codice qui return self;
In Sprite Kit la transizione è simile:
GameScene * gameScene = [[GameScene alloc] initWithSize: CGSizeMake (1024, 768)]; [self.scene.view presentScene: gameScene];
Il GameScene
deve essere del SKScene
categoria, e il -(Id) initWithSize: (CGSize) dimensioni
è l'inizializzatore personalizzato. Un semplice esempio:
-(id) initWithSize: (CGSize) size if (self = [super initWithSize: size]) // Il tuo codice return self;
Gli oggetti Sprite sono normalmente usati per visualizzare qualche tipo di immagine. Può avere diverse proprietà, ad esempio: rotazione, scala, posizione, frame, ID e altro. L'implementazione di Cocos2D e Sprite Kit è simile. L'implementazione di Cocos2D è:
CCSprite * aSprite; aSprite = [CCSprite spriteWithFile: @ "player.png"]; aSprite.scale = .5; aSprite.position = ccp (_size.width / 1.30, _size.height / 1.25); [self addChild: aSprite];
Mentre in Sprite Kit l'implementazione è:
SKSpriteNode * planeShadow = [SKSpriteNode spriteNodeWithImageNamed: @ "player.png"]; planeShadow.scale = 0.5; planeShadow.position = CGPointMake (CGRectGetMidX (self.frame) + 100, CGRectGetMidY (self.frame) +200); [self addChild: planeShadow];
Gli oggetti etichetta sono usati per visualizzare il testo. Può avere diverse proprietà, tra cui testo, dimensioni del testo, colore del testo, posizione e molte altre. L'implementazione di Cocos2D e Sprite Kit è simile. L'implementazione di Cocos2D è:
CCLabelTTF * label = [CCLabelTTF labelWithString: @ "Hello World" fontName: @ "Marker Felt" fontSize: 64]; // chiedi al direttore per la dimensione della finestra CGSize size = [[CCDirector sharedDirector] winSize]; label.position = ccp (size.width / 2, size.height / 2); [self addChild: label];
L'implementazione del kit Sprite è:
SKLabelNode * gameScene = [SKLabelNode labelNodeWithFontNamed: @ "Chalkduster"]; [gameScene setText: @ "New Game"]; [gameScene setFontSize: 18]; gameScene setPosition: CGPointMake (CGRectGetMidX (self.frame) + 5, CGRectGetMidY (self.frame) -40)]; [self addChild: gameScene];
In Cocos2D, i menu sono creati utilizzando due oggetti: CCMenu
e CCMenuItem
. L'esempio seguente presenta un menu con 2 opzioni in Cocos2D:
Dimensione CGSize = [[CCDirector sharedDirector] winSize]; [CCMenuItemFont setFontSize: 28]; CCMenuItem * itemNewGame = [CCMenuItemFont itemWithString: @ "Nuovo gioco" block: ^ (id sender) // Your code]; CCMenuItem * itemOptions = [CCMenuItemFont itemWithString: @ "Opzioni" block: ^ (id sender) NSLog (@ "Secondo elemento"); ]; Menu CCMenu * = [Menu CCMenuWithItems: itemNewGame, itemOptions, nil]; [menu alignItemsHorizontallyWithPadding: 20]; [menu setPosition: ccp (size.width / 2, size.height / 2 - 50)]; [autoaggiunta: menu];
SpiteKit non include alcun tipo di oggetto specifico del menu. È necessario creare un gestore di eventi su un oggetto specifico per attivarlo per l'input dell'utente. Quindi, per "creare" un menu devi usare un oggetto UIKit o un oggetto Sprite Kit.
Nell'esempio seguente viene utilizzato a SKLabelNode
come voce di menu. In primo luogo, definiamo il SKLabelNode
:
SKLabelNode * gameScene = [SKLabelNode labelNodeWithFontNamed: @ "Chalkduster"]; [gameScene setText: @ "New Game"]; [gameScene setFontSize: 18]; [gameScene setPosition: CGPointMake (CGRectGetMidX (self.frame) + 5, CGRectGetMidY (self.frame) -40)]; [self addChild: gameScene];
Dentro il -(vuoto) touchBegan: (NSSet *) tocca Evento: (UIEvent *) evento
metodo creeremo il gestore di eventi che intercetterà l'evento di tocco:
per (UITouch * tocco in tocco) Posizione CGPoint = [touch locationInNode: self]; if ([gameScene containsPoint: location]) // Scene Transition Animation SKTransition * reveal = [SKTransition revealWithDirection: SKTransitionDirectionDown duration: 1]; GameScene * gameScene = [[GameScene alloc] initWithSize: CGSizeMake (1024, 768)]; [self.scene.view presentScene: gameScene transition: reveal]; NSLog (@ "Touched gameScene !!!!");
Il codice di cui sopra fa diverse cose:
SKLabelNode
oggetto.La principale differenza tra Action e SKAction è che SKAction è un oggetto complesso con diverse proprietà. L'azione in Cocos2D è solo un'azione che il programmatore deve definire, chiamare e trattare.
Con Sprite Kit, SKAction offre diverse opzioni agli sviluppatori, come rotazione, ridimensionamento, ridimensionamento, ripetizione, dissolvenza, suono riprodotto e altro. SKaction può essere visto come un oggetto astratto che si occupa di qualsiasi tipo di azione, dal suono, agli sprite, ai nodi.
Ci concentreremo per il momento sulle azioni di movimento.
In Cocos2D dobbiamo definire uno scheduler per chiamare un metodo personalizzato:
[pianificazione personale: @selector (addSprite :) interval: 1];
E quindi definire il metodo personalizzato per fare l'animazione personalizzata.
- (void) addSprite: (ccTime) dt CCSprite * aMovableSprite = [CCSprite spriteWithFile: @ "frankenstein.png"]; aMovableSprite.scale = .8; [self 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; per (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];
In Sprite Kit, possiamo usare SKAction per controllare cosa succede a un oggetto all'inizio e alla fine del movimento. Le righe successive mostrano come spostare qualsiasi oggetto in linea retta:
SKSpriteNode * playerSprite = [SKSpriteNode spriteNodeWithImageNamed: @ "player.png"]; [playerSprite setScale: 0.4]; SKAction * movement = [SKAction moveTo: CGPointMake (900, 500) durata: 5]; SKAction * remove = [SKAction removeFromParent]; [playerSprite runAction: [SKAction sequence: @ [movement, remove]]]; [self addChild: playerSprite];
Tuttavia, possiamo definire un'azione personalizzata e utilizzare SKAction per attivare quell'azione. L'esempio seguente esemplifica un movimento di Bézier (simile alla versione di Action di Cocos2D). Si noti che è necessario definire uno scheduler per chiamare un metodo personalizzato.
SKAction * wait = [SKAction waitForDuration: 1]; SKAction * callEnemies = [SKAction runBlock: ^ [self sendNewSKSpriteNode]; ]; SKAction * updateSKSpriteNodeOnScreen = [sequenza di SKAction: @ [wait, callEnemies]]; [self runAction: [SKAction repeatActionForever: updateSKSpriteNodeOnScreen]];
Il metodo sendNewSKSpriteNode
gestirà il movimento dell'oggetto personalizzato.
-(void) sendNewSKSpriteNode CGRect screenRect = [[UIScreen mainScreen] bounds]; // Custom SKAction SKSpriteNode * enemy = [SKSpriteNode spriteNodeWithImageNamed: @ "frankenstein.png"]; enemy.scale = 0.6; CGMutablePathRef cgpath = CGPathCreateMutable (); // valori casuali float xStart = [self getRandomNumberBetween: 0 + enemy.size.width a: screenRect.size.width-enemy.size.width]; float xEnd = [self getRandomNumberBetween: 0 + enemy.size.width a: screenRect.size.width-enemy.size.width]; // ControlPoint1 float cp1X = [self getRandomNumberBetween: 0 + enemy.size.width a: screenRect.size.width-enemy.size.width]; float cp1Y = [self getRandomNumberBetween: 0 + enemy.size.width a: screenRect.size.width-enemy.size.height]; // ControlPoint2 float cp2X = [self getRandomNumberBetween: 0 + enemy.size.width a: screenRect.size.width-enemy.size.width]; float cp2Y = [self getRandomNumberBetween: 0 a: 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 durata: 5]; [autoaggiunta: nemico]; SKAction * remove2 = [SKAction removeFromParent]; [actionAzione nemica: [sequenza SKAction: @ [planeDestroy, remove2]]]; CGPathRelease (cgpath);
Cocos2D non ha alcun tipo di editor di particelle. Uno deve usare un'app esterna per creare la particella e quindi usare uno specifico CCParticleExplosion
proprietà per cambiare il suo comportamento. Dopo aver ottenuto la particella nel tuo progetto Xcode puoi chiamarla usando:
CCParticleExplosion * _particleExplosion; particleExplosion = [[CCParticleExplosion alloc] initWithTotalParticles: 800]; particleExplosion.texture = [[CCTextureCache sharedTextureCache] addImage: @ "texture.png"]; particleExplosion.life = 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); particleExplosion.gravity = 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; [self addChild: _particleExplosion]; particleExplosion.position = ccp (_size.width / 5, _size.height / 5); [particleExplosion resetSystem];
Gli emettitori sono utilizzati all'interno del kit Sprite per la generazione di particelle. Per poterli utilizzare, devi aggiungere una particella al tuo progetto. Vai a Nuovo -> File -> Resource -> Sprite Kit Particle File
. Poi dovresti nominarlo e scegliere qualsiasi tipo di particella (fuoco, magia, fumo, neve, tra gli altri). Ora vedrai che due nuovi file appariranno sul tuo progetto Xcode. Li implementerai 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); [self addChild: smokeTrail];
La classe SKEmitterNode è estesa e contiene diverse proprietà. Ti consigliamo di leggerlo per apprendere tutte le proprietà che un nodo emettitore può avere.
Il suono è una parte attiva di qualsiasi gioco o applicazione multimediale. In Cocos2D, possiamo ottenerlo con due passaggi. Il primo è includere il SimpleAudioEngine
file di intestazione.
#import "SimpleAudioEngine.h"
Quindi usi le seguenti linee per chiamare il file musicale all'interno del nostro progetto:
[[SimpleAudioEngine sharedEngine] playBackgroundMusic: @ loop "sound.caf": YES]; [[SimpleAudioEngine sharedEngine] setEffectsVolume: 0.4f];
A volte, Xcode non include automaticamente il file musicale in "Copy Bundle Resources". Se ciò accade, dovresti aggiungerlo manualmente.
Con Sprite Kit, le inclusioni di suoni sono semplici:
SKAction * soundAction = [SKAction playSoundFileNamed: @ "preview.mp3" waitForCompletion: NO]; [auto runAction: soundAction];
Nota che per realizzare questo con Sprite Kit hai usato ancora una volta l'oggetto SKAction.
Come puoi vedere dall'analisi precedente, Cocos2D e Sprite Kit hanno molte somiglianze. Cocos2D utilizza diversi livelli per ogni oggetto, mentre Sprite Kit incapsula più oggetti e usa la classe super NSObject per raggiungere determinati obiettivi (come pulsanti o menu).
In termini di facilità d'uso, Sprite Kit brilla davvero quando si desidera utilizzare il sistema Particle o l'esecutore di Action. Tuttavia, quando si lavora con oggetti più generali, entrambi i framework hanno lo stesso livello di difficoltà.
Ciononostante, la creazione di un gioco con Sprite Kit offre molti vantaggi chiave, tra cui un motore fisico completamente integrato, strumenti di flusso di lavoro semplificati in Xcode 5, compatibilità con iOS e OS X e manutenzione ufficiale di Apple.
La domanda è: quale userete per il vostro prossimo progetto di gioco 2D? Fateci sapere nei commenti.