Sprite Kit vs Cocos2D

Sprite Kit är en av de mest spännande nya teknologierna som finns med iOS 7 SDK och Xcode 5, men hur jämför den den med en etablerad spelmotor som Cocos2D? Denna handledning kommer att ge en kort introduktion till Sprite Kit innan du tar en omfattande titt på hur det staplar upp mot Cocos2D.


Introducerar Sprite Kit

Av alla tillgängliga spel i App Store är många av de mest nedladdade och mest lönsamma 2D-spelen. Några ikoniska titlar i denna kategori inkluderar Angry Birds, Tiny Wings och Cut the Reb. Att driva framgången för dessa spel är flera vanliga egenskaper: vacker grafik, partikeleffekter, en fysikmotor, sömlös animering och övertygande ljudeffekter.

Innan lanseringen av iOS 7 SDK släpptes, var det bara möjligt att bygga spel som dessa med hjälp av ramar och motorer från tredje part. Nu, med introduktionen av Sprite Kit behöver utvecklare inte titta längre än den inbyggda SDK för att hitta allt de behöver för att kunna bygga bra 2D och 2.5D-spel. Funktionen som tillhandahålls av Sprite Kit innehåller Sprites, Shapes, Particles (t ex brand, rök, etc.), animationer, fysik simulering, ljud, video och visuella effekter. Xcode 5 ger nu också stöd för texturförpackningar och partikeldesign.

Sprite Kit kan logiskt abstraheras i följande tre delar:

  • scener - Som i Cocos2D är scener det visuella lagret i spelet. Det är där du hanterar bakgrunden, föremålen (som träd, bilar, flygplan, avatarer osv.).
  • Åtgärder - Smidiga animeringar är en viktig del i något spel. Apple utformade handlingssystemet på ett intuitivt sätt, och det gör att du kan göra nästan vad som helst. Några av de vanligaste åtgärderna som presenteras är: flytta, blekna, skala, ändra storlek, rotera, animera med texturer och gruppåtgärder. Om en viss åtgärd inte är definierad kan du dessutom alltid skapa ett eget kodblock för att skapa din egen åtgärd och manipulera det objektet.
  • Fysik - Om du vill ha ett spel som uppträder realistiskt, behöver du lägga till en fysikmotor. Du vill inte ha en kula som inte följer en specifik bana, en boll som inte hoppa när den träffar marken och andra sådana amatöriska effekter. Lyckligtvis kommer Sprite Kit med en fysikmotor bakad i.

Varför Sprite Kit?

Det finns några väldigt stora fördelar med att ha en 2D och 2.5D spelplattform som tillhandahålls och underhålls av Apple. Tänk på följande punkter:

Native Performance

Inbyggd utveckling och inbyggda verktyg handlar om prestanda.

Trots det faktum att utvecklare vanligtvis vill att deras spel ska köras på så många olika plattformar som möjligt, kommer ett inbyggt spel nästan alltid att ha bättre prestanda än ett icke-inbyggt spel. Plus, om verktygen för att utveckla dessa spel är inbyggda kan man se till att koden är integrerad med plattformens ekosystem.

Platform Integration

Som nämnts ovan kombinerar Sprite Kit och Xcode 5 många av de väsentliga komponenterna för att bygga bra spel. Det innebär att utvecklingen kan bli mer strömlinjeformad och verktygen blir mer tillförlitliga och effektiva.

Framtida bevisutveckling

Att skriva ett spel med hjälp av en tredje parts ram- eller spelmotor är alltid ett tvåkantigt svärd. Vi vet aldrig om verktygen kommer att vara kompatibla med framtida plattformsuppdateringar, eller om spelet kommer att fungera bra efter en uppdatering. När saker bryts är det osäkert hur länge det tar samhället att fixa buggarna.

Cocos2D är ett exempel på ett open source-projekt som måste hantera detta problem. Koden utvecklas ständigt och vid varje ny release måste flera säkerhetssteg utföras för att garantera att applikationer som byggs med Cocos2D fortfarande kommer att köras på den senaste versionen av IOS och senaste hårdvaran.

Med Sprite Kit har Apple tillhandahållit en uppsättning verktyg för att säkerställa att spelkoden fungerar på alla kompatibla enheter utan problem. Observera att Sprite Kit inte bara är en iOS-ram. Utvecklare kan börja bygga Sprite Kit-spel för OS X, och det är en säker satsning på att Sprite Kit-spel kommer att köras på alla framtida iOS-enheter.

Utvecklarvänlig

Användarvänlighet var en viktig faktor bakom framgången med spelmotorer som Cocos2D. Generellt sett hittade utvecklare Cocos2D mycket lättare att implementera än andra inhemska alternativ som OpenGL ES. Med Cocos2D omvandlades alla API-samtal på låg nivå till enkla metoder.

Sprite Kit följer detta tillvägagångssätt och erbjuder hundratals metoder som gör spelet utvecklingsprocessen mycket enklare. Sprite Kit är också vänligt. Den har det anpassade, väl utformade Apple API och levereras med en komplett strukturerad dokumentation. Apple har gjort ett utmärkt jobb med att skärpa det här verktyget för tredjeparts devleopers att använda. Den största fördelen med allt är att den kommer fullt laddat med varje resurs som du behöver för att skapa ett spel. Fysik, ljudeffekter, partikeleffekter, texturer, scenhantering-allt ingår i en enda bunt.

Observera att vid den första presentationen av Sprite Kit, Ricardo Quesada, huvudutvecklaren av Cocos2D sa följande på Twitter:

Sprite Kit är mycket bra. Med mindre funktioner än Cocos2D, men bättre. Jag gillar fysikintegrationen.

Detta är högt beröm som kommer från en av de ledande sinnena bakom Cocos2D!


Sprite Kit & Cocos2D Egenskaper

Funktion Sprite Kit Cocos2d
Öppen källa Nej Ja
Objective-C Native Support Ja Ja
Grafikmotor Ja Ja
animationer Ja Ja
Fysik simulering Ja (Integrerad) Nej (kräver Box2D eller Chipmunk)
Partikeleffekter Ja Ja
Xcode Native Integration Ja Nej
Automatisk Atlas Creation Ja Nej
Inbyggd partikelredigerare Ja Nej
shaders Nej Ja
Kamera Nej Ja

Projektjämförelse

Så, hur ser projekt med varje spelmotor faktiskt ut? För att svara på denna fråga har författarna inkluderat den fullständiga källkoden för både ett Sprite Kit och ett Cocos2D-projekt. Du kan använda dessa projekt som en jämförelse på hög nivå av varje spelmotor.


Källkodjämförelse

I det här avsnittet kommer vi faktiskt att bryta upp vanliga uppgifter och koncept som visar hur de implementeras i både Cocos2D och Sprite Kit.

CClayer vs SKScene

CCLayer eller SkScene är huvudobjektet som används för att rita andra objekt. Du kan tänka på detta som standardvyn som kommer att ta emot alla objekt, animeringar och peka på händelser.

Övergången mellan scener i Cocos2D görs med följande steg:

 GameScene * gameScene = [[GameScene allokera init]; [[CCDirector sharedDirector] replaceScene: gameScene];

Observera att GameScene.h filen måste vara av CCLayer kategori och har den specifika initialiseraren tillgänglig.

 @interface GameScene: CCLayer  + (CCScene *) scen;

I GameScene.m, Den ursprungliga implementeringen är:

 +(CCScene *) scen CCScene * scene = [CCScene nod]; GameScene * layer = [GameScene nod]; [scen addChild: lager]; återvändande scen;  - (id) init if ((self = [super init])) // Din kod här returnera själv; 

I Sprite Kit är övergången liknande:

 GameScene * gameScene = [[GameScene allokera] initWithSize: CGSizeMake (1024, 768)]; [self.scene.view presentScene: gameScene]; 

De GameScene måste vara av SKScene kategori och -(Id) initWithSize: (CGSize) storlek är den anpassade initialisatorn. Ett enkelt exempel:

 -(id) initWithSize: (CGSize) storlek om (self = [super initWithSize: size]) // Din kod returnera själv; 

CCSprite vs SKSpriteNode

Spriteobjekt används normalt för att visa en viss bild. Det kan ha flera egenskaper, till exempel: rotation, skala, position, ramar, ids och mer. Implementeringen av både Cocos2D och Sprite Kit är liknande. Cocos2D-implementeringen är:

 CCSprite * aSprite; aSprite = [CCSprite spriteWithFile: @ "player.png"]; aSprite.scale = .5; aSprite.position = ccp (_size.width / 1.30, _size.height / 1.25); [self addChild: aSprite];

Medan i Sprite Kit är implementeringen:

 SKSpriteNode * planeShadow = [SKSpriteNode spriteNodeWithImageNamed: @ "player.png"]; planeShadow.scale = 0.5; planeShadow.position = CGPointMake (CGRectGetMidX (self.frame) + 100, CGRectGetMidY (self.frame) +200); [self addChild: planeShadow];

CCLabelTTF vs SKLabelNode

Etikettobjekt används för att visa text. Det kan ha flera egenskaper, inklusive text, textstorlek, textfärg, position och många andra. Implementeringen av både Cocos2D och Sprite Kit är liknande. Cocos2D-implementeringen är:

 CCLabelTTF * label = [CCLabelTTF labelWithString: @ "Hello World" fontName: @ "Marker Felt" fontSize: 64]; // fråga regissören för fönsterstorleken CGSize size = [[CCDirector sharedDirector] winSize]; label.position = ccp (size.width / 2, size.height / 2); [self addChild: label];

Sprite Kit implementeringen är:

 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];

CCMenu och CCMenuTem vs Sprite Kit Menu

I Cocos2D skapas menyerna med två objekt: CCMenu och CCMenuItem. I följande exempel presenteras en meny med 2 alternativ i Cocos2D:

 CGSize size = [[CCDirector sharedDirector] winSize]; [CCMenuItemFont setFontSize: 28]; CCMenuItem * itemNewGame = [CCMenuItemFont itemWithString: @ "New Game" block: ^ (id avsändare) // Din kod]; CCMenuItem * itemOptions = [CCMenuItemFont itemWithString: @ "Options" block: ^ (id avsändare) NSLog (@ "Second item"); ]; CCMenu * meny = [CCMenu menuWithItems: itemNewGame, itemOptions, nil]; [menyn alignItemsHorizontalallyWithPadding: 20]; [menyuppsättning: ccp (size.width / 2, size.height / 2 - 50)]; [self addChild: meny];

SpiteKit innehåller inte någon typ av menyspecifikt objekt. Du måste skapa en händelsehanterare till ett specifikt objekt för att aktivera det för användarinmatning. Så, för att "skapa" en meny måste du använda ett UIKit-objekt eller ett Sprite Kit-objekt.

Följande exempel använder a SKLabelNode som ett menyalternativ. Först definierar vi 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];

Inuti -(void) touchesBegan: (NSSet *) berörs medEvent: (UIEvent *) händelse metod vi kommer att skapa händelsehanteraren som kommer att avlyssna beröringsevenemanget:

 för (UITouch * berörs) CGPoint location = [touch locationInNode: self]; om ([gameScene containsPoint: plats]) // Scene Transition Animation SKTransition * reveal = [SKTransition revealWithDirection: SKTransitionDirectionDown duration: 1]; GameScene * gameScene = [[GameScene allokera] initWithSize: CGSizeMake (1024, 768)]; [self.scene.view presentScene: gameScene transition: reveal]; NSLog (@ "Touched gameScene !!!!"); 

Ovan nämnda kod gör flera saker:

  1. Aktiverar beröringshändelserna.
  2. Konverterar tappplatsen till den interna platsen.
  3. Testa om tappplatsen är inne i speletScene SKLabelNode objekt.
  4. Skapar en övergångsanimering.
  5. Ändrar scenen.

Åtgärd vs. SKAction

Huvudskillnaden mellan Action och SKAction är att SKAction är ett komplext objekt med flera egenskaper. Åtgärd i Cocos2D är bara en åtgärd som programmeraren måste definiera, ringa och behandla.

Med Sprite Kit erbjuder SKAction flera alternativ till utvecklarna, som rotation, resize, skala, repetera, blekna, spela ljud och mer. SKTION kan ses som ett abstrakt objekt som handlar om någon form av handling, från ljud till sprites, till noder.

Vi kommer att fokusera för tillfället på rörelseåtgärder.

I Cocos2D behöver vi definiera en schemaläggare för att ringa en anpassad metod:

 [självschema: @selector (addSprite :) interval: 1];

Och definiera sedan den anpassade metoden för att göra den anpassade animationen.

 - (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: ^ (CCNode * nod) NSLog (@ "Sprite free!"); ]; NSMutableArray * arrayBezier = [[NSMutableArray alloc] init]; ccBezierConfig bezier; id bezierAction1; float splitDuration = 6 / 6.0; för (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]; 

I Sprite Kit kan vi använda SKAction för att styra vad som händer med ett objekt i början och slutet av rörelsen. Nästa rader visar hur man flyttar objekt i rak linje:

 SKSpriteNode * playerSprite = [SKSpriteNode spriteNodeWithImageNamed: @ "player.png"]; [playerSprite setScale: 0.4]; SKAction * -rörelse = [SKAction moveTo: CGPointMake (900, 500) varaktighet: 5]; SKAction * remove = [SKAction removeFromParent]; [playerSprite runAction: [SKAction sekvens: @ [rörelse, ta bort]]]; [self addChild: playerSprite];

Vi kan dock definiera en anpassad åtgärd och använda SKAction för att aktivera den åtgärden. Följande exempel exemplifierar en Bézier-rörelse (liknande Cocos2D-versionen av åtgärd). Observera att vi måste definiera en schemaläggare för att ringa en anpassad metod.

 SKAction * wait = [SKAction waitForDuration: 1]; SKAction * callEnemies = [SKAction runBlock: ^ self sendNewSKSpriteNode]; ]; SKAction * updateSKSpriteNodeOnScreen = [SKAction sekvens: @ [vänta, callEnemies]]; [self runAction: [SKAction repeatActionForever: updateSKSpriteNodeOnScreen]];

Metoden sendNewSKSpriteNode hanterar den anpassade objektrörelsen.

 -(void) sendNewSKSpriteNode CGRect screenRect = [[UIScreen mainScreen] gränser]; // Anpassad SKAction SKSpriteNode * fiende = [SKSpriteNode spriteNodeWithImageNamed: @ "frankenstein.png"]; enemy.scale = 0,6; CGMutablePathRef cgpath = CGPathCreateMutable (); // slumpmässiga värden float xStart = [self getRandomNumberBetween: 0 + enemy.size.width till: screenRect.size.width-enemy.size.width]; float xEnd = [self getRandomNumberBetween: 0 + enemy.size.width till: screenRect.size.width-enemy.size.width]; // ControlPoint1 float cp1X = [self getRandomNumberBetween: 0 + enemy.size.width till: screenRect.size.width-enemy.size.width]; float cp1Y = [self getRandomNumberBetween: 0 + enemy.size.width till: screenRect.size.width-enemy.size.height]; // ControlPoint2 float cp2X = [self getRandomNumberBetween: 0 + enemy.size.width till: screenRect.size.width-enemy.size.width]; float cp2Y = [self getRandomNumberBetween: 0 till: 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]; [self addChild: fiende]; SKAction * remove2 = [SKAction removeFromParent]; [fiende runAction: [SKAction sekvens: @ [planetDestroy, remove2]]]; CGPathRelease (cgpath); 

CCParticleExplosion vs Emitter

Cocos2D har ingen form av partikelredigerare. Man måste använda en extern app för att skapa partikeln och sedan använda specifika CCParticleExplosion egenskaper för att ändra sitt beteende. När du har partikeln i ditt Xcode-projekt kan du ringa det med:

 CCParticleExplosion * _particleExplosion; partikelExplosion = [[CCParticleExplosion alloc] initWithTotalParticles: 800]; particleExplosion.texture = [[CCTextureCache sharedTextureCache] addImage: @ "texture.png"]; partikelExplosion.life = 0,0f; partikelexplosion.lifeVar = 0,708f; partikelexplosion.startSize = 40; partikelExplosion.startSizeVar = 38; partikelExplosion.endSize = 14; partikelExplosion.endSizeVar = 0; partikelExplosion.angle = 360; partikelExplosion.angleVar = 360; partikelexplosion.speed = 243; partikelexplosion.speedVar = 1; CGPoint g = CGPointMake (1,15, 1,58); partikelexplosion.gravity = g; ccColor4F startC = 0,89f, 0,56f, 0,36f, 1,0f; partikelExplosion.startColor = startC; ccColor4F endC = 1.0f, 0.0f, 0.0f, 1.0f; partikelExplosion.endColor = endC; [self addChild: _particleExplosion]; partikelExplosion.position = ccp (_size.width / 5, _size.height / 5); [particleExplosion resetSystem];

Emitterare används inom Sprite Kit för partikelgenerering. För att kunna använda dem måste du lägga till en partikel i ditt projekt. Gå till Ny -> Fil -> Resurs -> Sprite Kit Particle File. Därefter ska du namnge det och välja vilken typ av partikel (eld, magi, rök, snö, bland annat). Nu ser du att två nya filer kommer att visas på ditt Xcode-projekt. Du implementerar dem med:

 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];

Klassen SKEmitterNode är omfattande och innehåller flera egenskaper. Vi rekommenderar dig att läsa den för att lära sig alla objekt som en emitterskod kan ha.

SimpleAudioEngine vs Sprite Kit Sound

Ljud är en aktiv del av alla spel eller multimedia applikationer. I Cocos2D kan vi uppnå det med två steg. Den första är att inkludera SimpleAudioEngine header-fil.

 #import "SimpleAudioEngine.h"

Sedan använder du följande rader för att ringa musikfilen i vårt projekt:

 [[SimpleAudioEngine sharedEngine] playBackgroundMusic: @ "sound.caf" loop: YES]; [[SimpleAudioEngine sharedEngine] setEffectsVolume: 0.4f];

Ibland innehåller Xcode inte automatiskt musikfilen i "Kopiera paketresurser". Om det händer bör du lägga till det manuellt.

Med Sprite Kit är ljudintegrationen enkel:

 SKAction * soundAction = [SKAction playSoundFileNamed: @ "preview.mp3" waitForCompletion: NO]; [self runAction: soundAction];

Observera att för att uppnå detta med Sprite Kit användes återigen SKAction-objektet.


Slutsats

Som du kan se från ovanstående analys har Cocos2D och Sprite Kit många likheter. Cocos2D använder flera lager för varje objekt, medan Sprite Kit inkapslar fler objekt och använder NSObject superklassen för att uppnå vissa mål (som knappar eller menyer).

När det gäller användarvänlighet skiner Sprite Kit verkligen när du vill använda partikelsystemet eller Action Performer. Men när man arbetar med mer allmänna objekt är båda ramarna på ungefär samma svårighetsgrad.

Att bygga ett spel med Sprite Kit ger emellertid många viktiga fördelar, inklusive en helt integrerad fysikmotor, strömlinjeformade arbetsflödesverktyg i Xcode 5, kompatibilitet med både iOS och OS X och officiellt underhåll av Apple.

Frågan är: vilken kommer du att använda för ditt nästa 2D-spelprojekt? Låt oss veta i kommentarerna.