I denne opplæringen lærer du hvordan du bruker Apples Sprite Kit-rammeverk for å gjenopprette et Missile Command-spill for iPad. Underveis lærer du mer om flere kjernekonsepter som sprites, berøringer, fysikk, kollisjoner og eksplosjoner. Målet med den andre opplæringen er å legge til fysikk, kollisjoner og eksplosjoner. Den andre opplæringen utvider også spillopplevelsen ved å legge til en flerspiller-modus.
Husker du Missile Command? Atari ga ut det opprinnelige spillet 8. mars 1981. Det var et actionspill bygget for Arcade-systemer og ble svært populært rundt om i verden.
Siden utgivelsen i 1981 ble det gjort flere tilpasninger for ulike plattformer. Nå er det tid for deg å gjenskape det opprinnelige spillet ved hjelp av moderne teknologier, iOS, Objective-C og iPad.
Du kan fortsatt spille det opprinnelige spillet. Ta en titt over på IGN og gjenopplev noen av barndommens minner.Skjermbildet under gir deg en ide om hvordan sluttresultatet vil se ut. Hvis du liker det du ser, så la oss komme i gang.
For å fullføre denne opplæringen trenger du Xcode 5 og den nyeste iOS 7 SDK. Du kan laste ned Xcode 5 og SDK fra iOS Dev Center.
På slutten av hvert avsnitt finner du en eller flere utfordringer. Målet med disse utfordringene er å hjelpe deg med å lære teknikker og teknologier som brukes i denne opplæringen. Noen er enkle, mens andre blir mer utfordrende, og krever en god forståelse av Sprite Kit-rammen. Med unntak av den siste utfordringen, husk at utfordringene ikke er nødvendige for å fullføre opplæringen. Men vi håper du gir dem en prøve.
Hvis du har spørsmål om Sprite Kit-rammeverket, foreslår vi at du tar en titt på våre andre Sprite Kit-veiledninger på Mobiletuts+.
Start Xcode 5 og opprett et nytt Sprite Kit-prosjekt ved å velge Nytt> Prosjekt ... fra Fil Meny. Velg SpriteKit Game mal, nevne prosjektet ditt Rakettkommando, og velg iPad fra enheter Meny.
Med prosjektet satt opp, legg til prosjektets ressurser, som du kan laste ned ved hjelp av linken øverst på siden. Vi starter med å fokusere på MyScene
klasse. Innsiden MyScene.m
, Du finner to metoder, initWithSize:
og touchesBegan: withEvent:
.
I initWithSize:
, fjern eller kommentere koden som er relatert til SKLabelNode
eksempel som vi ikke trenger det i denne opplæringen. Ta en titt på den oppdaterte implementeringen av initWithSize:
under.
- (id) initWithSize: (CGSize) størrelse self = [super initWithSize: size]; hvis (selv) self.backgroundColor = [SKColor colorWithRed: 0.15 green: 0.15 blue: 0.3 alpha: 1.0]; returner selv;
I touchesBegan: withEvent:
, vi gjør noe lignende. For nå må metoden bare inneholde logikken for berøringsdeteksjon og plasseringen av brukerens berøring. Disse endringene vil gi deg en kompilervarsel, men vi vil bli kvitt det senere i denne opplæringen.
- (void) berørerBegan: (NSSet *) berører withEvent: (UIEvent *) hendelse for (UITouch * berør berøring) CGPoint location = [touch locationInNode: self];
Ditt neste skritt er å skape to nye klasser. Den første klassen, MenuScene
, vil bli brukt til hovedmenyen og andre klasse, multiscene
, vil bli brukt til multiplayer grensesnittet. Begge klassene er underklasser av SKScene
. De MyScene
klassen vil bli brukt til å implementere singleplayer grensesnittet.
Som vi så i MyScene
klasse, må vi implementere en initialiserer for hver klasse. For nå setter initialisereren bare scenens bakgrunnsfarge som vi så i MyScene.m
. Initialiseringen av MenuScene
klassen må også sette opp spilltittelen. For å gjøre det, må vi ta vare på noen få ting.
SKSpriteNode
gjenstand.zPosition
.skala
.stilling
.Ta en titt på implementeringen av initWithSize:
av MenuScene
klasse for avklaring.
- (id) initWithSize: (CGSize) størrelse self = [super initWithSize: size]; hvis (selv) self.backgroundColor = [SKColor colorWithRed: (198.0 / 255.0) grønn: (220.0 / 255.0) blå: (54.0 / 255.0) alfa: 1.0]; SKSpriteNode * title = [SKSpriteNode spriteNodeWithImageNamed: @ "title"]; title.zPosition = 2; title.scale = 0.4; title.position = CGPointMake (size.width / 2, size.height / 2); [self addChild: title]; returner selv;
Du bør nå ha en hovedmeny og en tittel. Det er på tide å oppdatere hovedvisningskontrollen slik at den viser menyen hver gang programmet startes. Åpen ViewController.m
, finn viewDidLoad
metode, og erstatte SKScene
eksempel med en forekomst av MenuScene
klassen som vist nedenfor.
- (void) viewDidLoad [super viewDidLoad]; // Konfigurer visningen. SKView * skView = (SKView *) self.view; skView.showsFPS = YES; skView.showsNodeCount = YES; // Opprett og konfigurer scenen. SKScene * scene = [Menyscene sceneWithSize: skView.bounds.size]; scene.scaleMode = SKSceneScaleModeAspectFill; // Presentere scenen. [skView presentScene: scene];
Ikke glem å importere headerfilen til MenuScene
klasse.
#import "ViewController.h" #import "MenuScene.h"
Flott. Det er på tide å bygge prosjektet ditt og kjøre det for å kontrollere at alt fungerer som det skal. Du bør se et grensesnitt som ligner skjermbildet nedenfor.
Utfordring: For å skape en unik opplevelse, utfordrer vi deg til å gjøre følgende.
MenuScene
tittelobjekt.Før du legger til objekter i spillet, må vi legge til evnen til å navigere i spillet. Erklære to UIButton
forekomster i MenuScene
klasse og en variabel, sizeGlobal
, av type CGSize
for å lagre størrelsen på skjermen. Sistnevnte vil hjelpe oss med å posisjonere objektene på skjermen. Oppdater MenuScene.m
som vist under.
#import "MenuScene.h" @interface MenuScene () CGSize sizeGlobal; UIButton * singlePlayerButton; UIButton * multiPlayerButton; @slutt
Sett sizeGlobal
til størrelse
i klassens initialiserer som vist i kodestykket nedenfor.
- (id) initWithSize: (CGSize) størrelse self = [super initWithSize: size]; hvis (selv) self.backgroundColor = [SKColor colorWithRed: (198.0 / 255.0) grønn: (220.0 / 255.0) blå: (54.0 / 255.0) alfa: 1.0]; SKSpriteNode * title = [SKSpriteNode spriteNodeWithImageNamed: @ "title"]; title.zPosition = 2; title.scale = 0.4; title.position = CGPointMake (size.width / 2, size.height / 2); [self addChild: title]; sizeGlobal = size; returner selv;
Deretter erklæres tre metoder i MenuScene
klasse.
didMoveToView:
å presentere knappene når spillet overgår til menyvisningen.moveToSinglePlayerGame
som overgår spillet til MyScene
scene og fjerner knappene.moveToMultiPlayerGame
som overgår spillet til multiscene
scene og fjerner også knappene.I didMoveToView:
, programmet verifiserer om scenen overgangen fant sted uten problemer. Hvis det ikke oppstod noen problemer, laster applikasjonen ressursene, viser dem til brukeren og instanser knappene.
- (void) didMoveToView: (SKView *) visning UIImage * buttonImageNormal = [UIImage imageNamed: @ "singleBtn.png"]; singlePlayerButton = [UIButton buttonWithType: UIButtonTypeRoundedRect]; singlePlayerButton.frame = CGRectMake (sizeGlobal.height / 8, sizeGlobal.width / 2 + 250, buttonImageNormal.size.width, buttonImageNormal.size.height); singlePlayerButton.backgroundColor = [UIColor clearColor]; [singlePlayerButton setTitleColor: [UIColor whiteColor] forState: UIControlStateNormal]; UIImage * strechableButtonImageNormal = [buttonImageNormal stretchableImageWithLeftCapWidth: 12 topCapHeight: 0]; [singlePlayerButton setBackgroundImage: strechableButtonImageNormal forState: UIControlStateNormal]; [singlePlayerButton addTarget: selvhandling: @selector (moveToSinglePlayerGame) forControlEvents: UIControlEventTouchUpInside]; [self.view addSubview: singlePlayerButton]; Ullmage * buttonImageNormal2 = [UIImage imageNamed: @ "multiBtn.png"]; multiPlayerButton = [UIButton buttonWithType: UIButtonTypeRoundedRect]; multiPlayerButton.frame = CGRectMake (sizeGlobal.height / 2 + 100, sizeGlobal.width / 2 + 250, buttonImageNormal2.size.width, buttonImageNormal2.size.height); multiPlayerButton.backgroundColor = [UIColor clearColor]; [multiPlayerButton setTitleColor: [UIColor whiteColor] forState: UIControlStateNormal]; UIImage * strechableButtonImageNormal2 = [buttonImageNormal2 stretchableImageWithLeftCapWidth: 12 topCapHeight: 0]; [multiPlayerButton setBackgroundImage: strechableButtonImageNormal2 forState: UIControlStateNormal]; [multiPlayerButton addTarget: selvhandling: @selector (moveToMultiPlayerGame) forControlEvents: UIControlEventTouchUpInside]; [self.view addSubview: multiPlayerButton];
I didMoveToView:
, vi ringer moveToSinglePlayerGame
og moveToMultiPlayerGame
. La oss implementere disse metodene neste. I hver metode må vi gjøre følgende.
MyScene
eller multiscene
.Kan du implementere disse metodene alene? Hvis du er usikker, ta en titt på implementeringene nedenfor.
- (void) moveToSinglePlayerGame SKScene * scene = [MyScene sceneWithSize: self.view.bounds.size]; scene.scaleMode = SKSceneScaleModeAspectFill; SKTransition * overgang = [SKTransition revealWithDirection: SKTransitionDirectionLeft varighet: 1]; SKView * skView = (SKView *) self.view; [skView presentScene: sceneovergang: overgang]; [singlePlayerButton removeFromSuperview]; [multiPlayerButton removeFromSuperview];
- (void) moveToMultiPlayerGame SKScene * scene = [MultiScene sceneWithSize: self.view.bounds.size]; scene.scaleMode = SKSceneScaleModeAspectFill; SKTransition * overgang = [SKTransition revealWithDirection: SKTransitionDirectionLeft varighet: 1]; SKView * skView = (SKView *) self.view; [skView presentScene: sceneovergang: overgang]; [singlePlayerButton removeFromSuperview]; [multiPlayerButton removeFromSuperview];
Ikke glem å legge til en importerklæring for headerfiler av MyScene
og multiscene
.
#import "MenuScene.h" #import "MyScene.h" #import "MultiScene.h" @interface MenuScene () CGSize sizeGlobal; UIButton * singlePlayerButton; UIButton * multiPlayerButton; @slutt
Bygg prosjektet ditt og kjør programmet i iOS-simulatoren eller på en fysisk enhet. Spillet skal nå se ut som skjermbildet nedenfor.
Hovedmenyen er ferdig. Det er på tide å fokusere på spillets singleplayer-grensesnitt (MyScene
). De MyScene
klassen vil inneholde det meste av spillets logikk. Det første trinnet er å plassere kulefotograferingsblomstene nederst på skjermen. Vi lager tre blomster, som hver vil ha unike egenskaper.
Du vil også spore antall eksploderte missiler og vise den verdien i en annen SKLabelNode
oppkalt labelMissilesExploded
. Som du kan se nedenfor, trenger vi en rekke instansvariabler eller ivar
s. Hensikten med hver ivar blir klar når vi oppdaterer initWithSize:
metode i MyScene
.
#import "MyScene.h" @interface MyScene () CGSize sizeGlobal; SKLabelNode * labelflowerBullets1; SKLabelNode * labelflowerBullets2; SKLabelNode * labelflowerBullets3; SKLabelNode * labelMissilesExploded; int posisjon; int monstersDead; int missileExploded; int flowerBullets1; int flowerBullets2; int flowerBullets3; @slutt
I initWithSize:
, Vi instantierer og konfigurerer de ulike SKLabelNode
forekomster.
- (id) initWithSize: (CGSize) størrelse if (selv = [super initWithSize: size]) self.backgroundColor = [SKColor colorWithRed: (198.0 / 255.0) grønn: (220.0 / 255.0) blå: (54.0 / 255.0) alpha : 1,0]; posisjon = size.width / 3; sizeGlobal = size; [self addFlowerCommand]; // Etikett Informere Missiler Sprengt labelMissilesExploded = [SKLabelNode labelNodeWithFontNamed: @ "Hiragino-Kaku-Gothic-ProN"]; labelMissilesExploded.text = [NSString stringWithFormat: @ "Missiler eksplodert:% d", missileExploded]; labelMissilesExploded.fontSize = 30; labelMissilesExploded.position = CGPointMake (size.width / 2, size.height-labelMissilesExploded.frame.size.height); labelMissilesExploded.zPosition = 3; [self addChild: labelMissilesExploded]; flowerBullets1 = 10; flowerBullets2 = 10; flowerBullets3 = 10; labelflowerBullets1 = [SKLabelNode labelNodeWithFontNamed: @ "Hiragino-Kaku-Gothic-ProN"]; labelflowerBullets1.text = [NSString stringWithFormat: @ "% d", flowerBullets1]; labelflowerBullets1.fontSize = 30; labelflowerBullets1.position = CGPointMake (posisjon-posisjon / 2, labelflowerBullets1.frame.size.height / 2); labelflowerBullets1.zPosition = 3; [self addChild: labelflowerBullets1]; labelflowerBullets2 = [SKLabelNode labelNodeWithFontNamed: @ "Hiragino-Kaku-Gothic-ProN"]; labelflowerBullets2.text = [NSString stringWithFormat: @ "% d", flowerBullets2]; labelflowerBullets2.fontSize = 30; labelflowerBullets2.position = CGPointMake (posisjon * 2-posisjon / 2, labelflowerBullets2.frame.size.height / 2); labelflowerBullets2.zPosition = 3; [self addChild: labelflowerBullets2]; labelflowerBullets3 = [SKLabelNode labelNodeWithFontNamed: @ "Hiragino-Kaku-Gothic-ProN"]; labelflowerBullets3.text = [NSString stringWithFormat: @ "% d", flowerBullets3]; labelflowerBullets3.fontSize = 30; labelflowerBullets3.position = CGPointMake (posisjon * 3-posisjon / 2, labelflowerBullets3.frame.size.height / 2); labelflowerBullets3.zPosition = 3; [self addChild: labelflowerBullets3]; returner selv;
I initWithSize:
, vi ringer også addFlowerCommand
, som vi ikke har dekket ennå. Implementeringen er ikke vanskelig som du kan se nedenfor. I addFlowerCommand
, vi instanser tre SKSpriteNode
forekomster, en for hver blomst, og plasser dem nederst på skjermen ved hjelp av stilling
.
- (void) addFlowerCommand for (int i = 1; i <= 3; i++) SKSpriteNode *flower = [SKSpriteNode spriteNodeWithImageNamed:@"flower.png"]; flower.zPosition = 2; flower.position = CGPointMake(position * i - position / 2, flower.size.height / 2); [self addChild:flower];
Du kan nå bygge prosjektet og kjøre det i iOS Simulator for å se spillets enkeltspiller grensesnitt.
Vi har blomster, men vi trenger fortsatt noen monstre. Det er på tide å gjennomføre addMonstersBetweenSpace:
metode. I denne metoden lager vi tre monstre og plasserer dem mellom blomstene. Monsternes posisjon bestemmes av spaceOrder
variabel. Vi plasserer tilfeldigvis monstrene ved å bruke getRandomNumberBetween: til:
, som genererer et tilfeldig tall mellom to gitt tall.
- (void) addMonstersBetweenSpace: (int) spaceOrder for (int i = 0; i< 3; i++) int giveDistanceToMonsters = 60 * i -60; int randomMonster = [self getRandomNumberBetween:0 to:1]; SKSpriteNode *monster; if (randomMonster == 0) monster = [SKSpriteNode spriteNodeWithImageNamed:@"protectCreature4"]; else monster = [SKSpriteNode spriteNodeWithImageNamed:@"protectCreature2"]; monster.zPosition = 2; monster.position = CGPointMake(position * spaceOrder - giveDistanceToMonsters, monster.size.height / 2); [self addChild:monster];
Gjennomføringen av getRandomNumberBetween: til:
er vist nedenfor.
- (int) getRandomNumberBetween: (int) fra til: (int) til return (int) fra + arc4random ()% (til - fra + 1);
Vi påberoper addMonstersBetweenSpace:
to ganger i initWithSize:
metode av MyScene
klasse.
- (id) initWithSize: (CGSize) størrelse if (selv = [super initWithSize: size]) self.backgroundColor = [SKColor colorWithRed: (198.0 / 255.0) grønn: (220.0 / 255.0) blå: (54.0 / 255.0) alpha : 1,0]; // ... // // Legg til Monsters [self addMonstersBetweenSpace: 1]; [self addMonstersBetweenSpace: 2]; returner selv;
Nå som vi har blomster og monstre, er det på tide å legge til missiler. Vi må gjøre følgende for å oppnå dette.
SKAction
å påberope en metode.SKAction
å gjenta denne handlingen.addMissilesFromSky:
, som vil tilfeldig generere tre nye raketter og legge dem til scenen. Vi vil erklære SKAction
forekomster i initWithSize:
. Ta en titt på den oppdaterte implementeringen av initWithSize:
under.
- (id) initWithSize: (CGSize) størrelse if (selv = [super initWithSize: size]) self.backgroundColor = [SKColor colorWithRed: (198.0 / 255.0) grønn: (220.0 / 255.0) blå: (54.0 / 255.0) alpha : 1,0]; // ... // // Opprett handlinger SKAction * wait = [SKAction waitForDuration: 2]; SKAction * createMissiles = [SKAction runBlock: ^ [self addMissilesFromSky: size]; ]; SKAction * updateMissiles = [SKAction sekvens: @ [vent, createMissiles]]; [self runAction: [SKAction repeatActionForever: updateMissiles]]; returner selv;
Gjennomføringen av addMissilesFromSky:
er vist nedenfor.
- (void) addMissilesFromSky: (CGSize) størrelse int numberMissiles = [self getRandomNumberBetween: 0 to: 3]; for (int i = 0; i < numberMissiles; i++) SKSpriteNode *missile; missile = [SKSpriteNode spriteNodeWithImageNamed:@"enemyMissile"]; missile.scale = 0.6; missile.zPosition = 1; int startPoint = [self getRandomNumberBetween:0 to:size.width]; missile.position = CGPointMake(startPoint, size.height); int endPoint = [self getRandomNumberBetween:0 to:size.width]; SKAction *move =[SKAction moveTo:CGPointMake(endPoint, 0) duration:15]; SKAction *remove = [SKAction removeFromParent]; [missile runAction:[SKAction sequence:@[move,remove]]]; [self addChild:missile];
Hvis du bygger og kjører din søknad, bør resultatet se ut som skjermbildet nedenfor.
Utfordring: Dette er flott, men vi trenger virkelig flere monstre. Vi utfordrer deg til å gjøre følgende.
Vi kan se litt bevegelse, men vi trenger nøkkelkomponenten i spillet, brukerinteraksjon. Vi legger til brukerinteraksjon ved å utnytte to metoder, touchesBegan: withEvent:
og positionOfWhichFlowerShouldBegin:
. For å legge til brukerinteraksjon må vi ta hensyn til følgende.
Den oppdaterte implementeringen av touchesBegan: withEvent:
er vist nedenfor.
- (void) berørerBegan: (NSSet *) berører withEvent: (UIEvent *) hendelse for (UITouch * berør berøring) CGPoint location = [touch locationInNode: self]; // Returner om brukerkraner under en blomst hvis (location.y < 120) return; int bulletBeginning = 0; if (location.x >= 0 && location.x < position) bulletBeginning = position-position/2; if (flowerBullets1 > 0) flowerBullets1--; ellers if (flowerBullets1 == 0 && flowerBullets2> 0) flowerBullets2--; [labelflowerBullets2 setText: [NSString stringWithFormat: @ "% d", flowerBullets2]]; bulletBeginning = [selvposisjonOfWhichFlowerShouldBegin: 2]; annet hvis (flowerBullets3> 0) flowerBullets3--; [labelflowerBullets3 setText: [NSString stringWithFormat: @ "% d", flowerBullets3]]; bulletBeginning = [selvposisjonOfWhichFlowerShouldBegin: 3]; ellers return; [labelflowerBullets1 setText: [NSString stringWithFormat: @ "% d", flowerBullets1]]; annet hvis ((location.x> = posisjon && location.x < position*2)) bulletBeginning = position*2-position/2; if(flowerBullets2 > 0) flowerBullets2--; ellers hvis (sted.x < sizeGlobal.width/2) if(flowerBullets1 > 0) flowerBullets1--; [labelflowerBullets1 setText: [NSString stringWithFormat: @ "% d", flowerBullets1]]; bulletBeginning = [selvposisjonOfWhichFlowerShouldBegin: 1]; annet hvis (flowerBullets3> 0) flowerBullets3--; [labelflowerBullets3 setText: [NSString stringWithFormat: @ "% d", flowerBullets3]]; bulletBeginning = [selvposisjonOfWhichFlowerShouldBegin: 3]; ellers return; else if (flowerBullets3> 0) flowerBullets3--; [labelflowerBullets3 setText: [NSString stringWithFormat: @ "% d", flowerBullets3]]; bulletBeginning = [selvposisjonOfWhichFlowerShouldBegin: 3]; annet hvis (flowerBullets1> 0) flowerBullets1--; [labelflowerBullets1 setText: [NSString stringWithFormat: @ "% d", flowerBullets1]]; bulletBeginning = [selvposisjonOfWhichFlowerShouldBegin: 1]; ellers return; [labelflowerBullets2 setText: [NSString stringWithFormat: @ "% d", flowerBullets2]]; else bulletBeginning = posisjon * 3-posisjon / 2; hvis (flowerBullets3> 0) flowerBullets3--; ellers if (flowerBullets3 == 0 && flowerBullets2> 0) flowerBullets2--; [labelflowerBullets2 setText: [NSString stringWithFormat: @ "% d", flowerBullets2]]; bulletBeginning = [selvposisjonOfWhichFlowerShouldBegin: 2]; annet hvis (flowerBullets1> 0) flowerBullets1--; [labelflowerBullets1 setText: [NSString stringWithFormat: @ "% d", flowerBullets1]]; bulletBeginning = [selvposisjonOfWhichFlowerShouldBegin: 1]; ellers return; [labelflowerBullets3 setText: [NSString stringWithFormat: @ "% d", flowerBullets3]];
Selv om det er mye kode for å gå gjennom, er det ikke så komplisert. Du kontrollerer om det er noen kuler igjen for hver blomst og oppdag sonen der brukeren tappet ved å påkalle positionOfWhichFlowerShouldBegin:
, som vi skal diskutere om et øyeblikk. Samtidig kontrollerer vi om brukeren tappet under blomsten, noe som forhindrer blomsten i å skyte en kule.
hvis (location.y < 120) return;
De positionOfWhichFlowerShouldBegin:
Metoden returnerer posisjonen som tilsvarer en bestemt sone der brukeren har tappet. Husk at du delte skjermen i tre deler for å plassere de tre blomstene, slik at du må oppdage sonen der brukeren har tappet og lenke den til en av blomstene. Blomsten som skyter kulen, vil være den nærmeste til brukerens trykk. Dette er hva implementeringen av positionOfWhichFlowerShouldBegin:
ser ut som.
- (int) posisjonOfWhichFlowerShouldBegin: (int) nummer returposisjon * nummer - posisjon / 2;
For å få kulene til å flytte, må vi opprette en annen SKSpriteNode
forekomst. Hver kule har en varighet og en SKAction
forbundet med det. Denne logikken er også inkludert i touchesBegan: withEvent:
. Ta en titt på den oppdaterte gjennomføringen nedenfor.
- (void) berørerBegan: (NSSet *) berører withEvent: (UIEvent *) hendelse for (UITouch * berør berøring) CGPoint location = [touch locationInNode: self]; // ... // SKSpriteNode * bullet = [SKSpriteNode spriteNodeWithImageNamed: @ "flowerBullet"]; bullet.zPosition = 1; bullet.scale = 0,6; bullet.position = CGPointMake (bulletBeginning, 110); bullet.color = [SKColor redColor]; bullet.colorBlendFactor = 0.5; float duration = (2 * location.y) /sizeGlobal.width; SKAction * move = [SKAction moveTo: CGPointMake (location.x, location.y) varighet: varighet]; SKAction * remove = [SKAction removeFromParent]; [bullet runAction: [SKAction sekvens: @ [move, remove]]]; [self addChild: bullet];
Hvis du bygger og driver søknaden din, bør blomstene kunne skyte kuler. De eksploderer ikke ennå, men vi tar vare på det i neste opplæring.
Utfordring: Er du opp for en annen utfordring? Ta en titt på disse utfordringene.
Hvis du har fulgt trinnene i denne opplæringen, bør du nå ha grunnlaget for Missile Command-spillet ved hjelp av Sprite Kit-rammen. Hvis du har spørsmål eller tilbakemelding, er du velkommen til å legge igjen en kommentar nedenfor.