iOS SDK Bygg et fakta-spill - Grensesnittoppretting

Denne opplæringen vil lære deg hvordan du bruker Sprite Kit-rammeverket for å lage et spørsmålbasert Fakta-spill. Den er designet for både nybegynnere og avanserte brukere. Underveis vil du bruke Sprite Kit-kjernen. Fakta Game-opplæringen er delt inn i tre deler for å dekke hver seksjon helt. Etter denne tre delveiledningen vil leserne kunne lage et enkelt spørsmål og svar-trykkspill med lyder, animasjoner, menyer, regler, timere og UIKit-interaksjon.


Introduksjon

Denne serien er delt inn i tre deler: Prosjektoppsett, Grensesnittoppretting og Game Logic. Hver del vil gi et praktisk resultat, og summen av alle deler vil produsere det endelige spillet. Til tross for at hver del kan leses selvstendig, for bedre forståelse og veiledning, foreslår vi at opplæringen følges trinnvis. Vi har også inkludert kildekoden for hver del separat. Dermed gir en måte å starte opplæringen i noen del av serien.

Dette er den andre delen av vår Fakta Game med Sprite Kit opplæringsserie. I denne opplæringen vil du programmere nivåvalg og hovedspillets grensesnitt. Denne opplæringen fokuserer på flere aspekter som tilpasset UITableView, tilpasset klasse initialiserere, eiendomslister og SKActions. Vi vil forklare alt nærmere nedenfor. Hvis du ikke har fullført første del av serien ennå, kan du laste ned prosjektet og henting nøyaktig hvor vi sluttet.

Slik ser vi sluttresultatet ut:


Illustrasjon av det endelige resultatet - fakta

1. Nivå Velg

Trinn 1

Hovedmålet med dette spillet er å skape flere spørsmål delt på flere nivåer. På denne måten må du danne et tilpasset grensesnitt for å velge nivået du vil spille. For å oppnå dette må du legge til en annen Objective-C klasse (Fil -> Ny -> Fil). Navngi det LevelSelect og velg SKScene som superklassen. Du vil se to nye filer i prosjektet ditt.

For nivåvalg, vil du bruke UITableView se og konfigurere det med flere egenskaper. I tillegg må du også nevne nivåene og beskrivelsene deres. I LevelSelect.h du bør legge til disse egenskapene. Følgende utdrag vil hjelpe deg:

 @property (nonatomic, behold) UIButton * backButton; @property (behold, nonatomic) IBOutlet UITableView * tableView; @property (strong, nonatomic) NSArray * levelsArray; @property (strong, nonatomic) NSArray * levelsDescriptionArray;

Utdraget inneholder også a UIButton kalt backButton. For øyeblikket er knappen selvforklarende; det hjelper brukeren å gå tilbake fra nivåvalggrensesnittet til hovedgrensesnittet.

Steg 2

Deretter fokusere på LevelSelect.m. Det første trinnet er å legge til -(Id) initWithSize: (CGSize) størrelse metode. I denne klassen konfigurerer du bare bakgrunnsfargen. Du kan velge hvilken farge du liker mest.

 -(id) initWithSize: (CGSize) størrelse hvis (selv = [super initWithSize: size]) self.backgroundColor = [SKColor colorWithRed: 0.25 green: 0.35 blue: 0.15 alpha: 1.0];  returner selv; 

Siden du bruker UIKit visninger, du må legge til -(void) didMoveToView: (SKView *) visning metode. Denne metoden definerer og konfigurerer backButton og tableView, plasserer en titteletikett for visningen, tildeler og initialiserer nivåeneArray og nivåeneDescriptionArray, og legger tabellvisningen til hovedvisningen. De tilbake knapp kan konfigureres som følger:

 _backButton = [UIButton buttonWithType: UIButtonTypeRoundedRect]; _backButton.frame = CGRectMake (CGRectGetMidX (self.frame) -100, CGRectGetMaxY (self.frame) -100, 200, 70.0); _backButton.backgroundColor = [UIColor clearColor]; [_backButton setTitleColor: [UIColor whiteColor] forState: UIControlStateNormal]; Ullmage * buttonExitImageNormal = [UIImage imageNamed: @ "back.png"]; UIImage * strechableButtonExitImageNormal = [buttonExitImageNormal stretchableImageWithLeftCapWidth: 12 topCapHeight: 0]; [_backButton setBackgroundImage: strechableButtonExitImageNormal forState: UIControlStateNormal]; [_backButton addTarget: selvhandling: @selector (moveToHome) forControlEvents: UIControlEventTouchUpInside]; [self.view addSubview: _backButton];

I tillegg må du opprette moveToHomemetode og importere de MyScene.h.

 -(void) moveToHome MyScene * myScene = [[MyScene alloker] initWithSize: CGSizeMake (CGRectGetMaxX (self.frame), CGRectGetMaxY (self.frame))]; [self removeUIViews]; [self.scene.view presentScene: myScene]; 

Siden du må fjerne UIKIt visninger på mer enn ett sted, la oss lage en metode som gjør akkurat det. Metoden kalles removeUIViews og er vist nedenfor:

 -(void) removeUIViews [_backButton removeFromSuperview]; [_tableView removeFromSuperview]; 

Etiketten til dette grensesnittet er veldig enkelt. Prøv å programmere det selv. Hvis du har problemer, vil følgende utdrag hjelpe deg.

 SKLabelNode * titleLabel = [SKLabelNode labelNodeWithFontNamed: @ "Chalkduster"]; titleLabel.text = @ "Level Select !!"; titleLabel.fontSize = 60; titleLabel.position = CGPointMake (CGRectGetMidX (self.frame), CGRectGetMidY (self.frame) +300); [self addChild: titleLabel];

Trinn 3

De Tableview konfigurasjonen er litt vanskelig siden vi må konfigurere flere egenskaper, for eksempel rammestørrelse og plassering, datakilde og en delegat.

 _tableView = [[UITableView alloc] initWithFrame: CGRectMake (CGRectGetMidX (self.frame) -150, CGRectGetMidY (self.frame) -250, 300, 400)]; _tableView.dataSource = selv; _tableView.delegate = selv;

Den andre og tredje linjen i den nevnte koden krever et ekstra trinn, siden du samtidig definerer to visninger. Datakilden til UITableView er selvdefinert og UITableView har en handling delegat. I LevelSelect.h du bør utvide klassen din med UITableViewDataSource og UITableViewDelegate. Din LevelSelect.h skal se ut som:

 @interface LevelSelect: SKScene < UITableViewDataSource, UITableViewDelegate >

Siden du forlenger UITableViewDataSource og UITableViewDelegate, Ytterligere metoder må implementeres, nemlig:

  1. -(NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) seksjon
  2. -(UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath

Den første er kun kjent i realtid antall rader som finnes i tabellvisningen. Den andre metoden er kompleks, siden den brukes til å fylle ut og konfigurere tabellvisningen. Tabellvisningskonfigurasjonen dekker tittelen, beskrivelsen og et radbilde. For å bruke beskrivelsen i hver rad må vi initialisere hver celle med UITableViewCellStyleSubtitle celle stil.

Denne metoden er ansvarlig for et ekstra trinn: det verifiserer nåværende spillers nivå og deaktiverer nivåene foran actualPlayerLevel. Den fulle metoden deklarasjonen kan ses nedenfor:

 -(UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath NSString * levels = [_levelsArray objectAtIndex: indexPath.row]; NSString * beskrivelser = [_levelsDescriptionArray objectAtIndex: indexPath.row]; UITableViewCell * celle = [tableView dequeueReusableCellWithIdentifier: @ "Identifier"]; hvis (celle == nil) celle = [[UITableViewCell allokere] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: @ "Identifier"];  hvis (indexPath.row> = actualPlayerLevel) [celle setUserInteractionEnabled: FALSE]; [cell.textLabel setText: levels]; cell.imageView.image = [UIImage imageNamed: @ "appleLogo.png"]; [cell.detailTextLabel setText: descriptions]; returcelle; 
 -(NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) seksjon return [_levelsArray count]; 

Her er to notater om -(UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath metode. Du har ennå ikke initialisert egenskapene levelsArray, levelsDescriptionArray og actualPlayerLevel. Alt vil bli definert i -(void) didMoveToView: (SKView *) visning metode. Ikke glem å legge til actualPlayerLevel eiendom til din klasse:

 @implementation LevelSelect long actualPlayerLevel; 

Trinn 4

De levelsArray er definert med navnene på nivåene. Du kan kalle det "Nivå 1", "Nivå 2", eller et annet navn etter eget valg. De levelsDescriptionArray følger samme prinsipp, det er en beskrivelse for hvert nivå og kan defineres med navn etter eget valg. En mulig implementering er:

 _levelsArray = [[NSArray alloker] initWithObjects: @ "Level 1.", @ "Level 2.", @ "Level 3.", @ "Level 4.", @ "Level 5.", @ "Level 6." , @ "Nivå 7.", @ "Nivå 8.", @ "Nivå 9", null); _levelsDescriptionArray = [[NSArray alloc] initWithObjects: @ "Eventyret begynner.", @ "Et nytt trinn.", @ "Achivements ?!", @ "Nivå 4 beskrivelse", @ "Nivå 5 beskrivelse", @ "Nivå 6 beskrivelse ", @" Nivå 7 beskrivelse ", @" Nivå 8 beskrivelse ", @" Nivå 9 beskrivelse ", null);

Endelig, den actualPlayerLevel er en lang verdi type som representerer nivået av spilleren. For nå, si at dagens nivå er 1.

 actualPlayerLevel = 1;

De -(void) didMoveToView: (SKView *) visning Metoden slutter når du legger til tabellvisningen til skjermen:

 [self.view addSubview: _tableView];

Til slutt trenger du en ekstra endring i MyScene.m -(void) moveToGame metode. Du må ringe denne nye klassen i stedet for den gamle. Det kan lett oppnås gjennom:

 -(void) moveToGame LevelSelect * factsScene = [[LevelSelect alloc] initWithSize: CGSizeMake (CGRectGetMaxX (self.frame), CGRectGetMaxY (self.frame))]; // Samme kode // ...

På dette punktet bør du Løpe prosjektet og test det nye grensesnittet. Du bør se noe som ligner på neste bilde:

Illustrasjon av skjermbildet Nivåvalg

2. Fakta Grensesnitt

Trinn 1

Fakta grensesnittet er der den virkelige handlingen skjer. Grensesnittet har flere visninger som direkte oversettes til egenskaper, for eksempel antall gjenværende liv, nåværende nivå, en timer og sanne og falske knapper. Videre, for denne klassen vil du opprette en tilpasset initialiserer. Fordelen med denne tilpassede initialiseringen er at vi kan gå videre gjennom spillet og verdiene angående nivået. Livene blir også overført til klassen, og klassen reagerer (parser data) tilsvarende.

Igjen, vil vi bruke SKLabelNode, UIButtons, og a NSMutableArray. Den komplette FactsScene.h er følgende:

 @interface FactsScene: SKScene NSMutableArray * heartArray;  @property (nonatomic, weak) SKLabelNode * currentLevelLabel; @property (nonatomic, weak) SKLabelNode * timerLevel; @property (nonatomic, behold) UIButton * trueButton; @property (nonatomic, behold) UIButton * falseButton; - (id) initWithSize: (CGSize) størrelse inLevel: (NSInteger) nivå medPlayerLives: (int) lives;

Nå er det på tide å flytte til FactsScene.m og implementere noen få objekter. Du trenger ytterligere objekter for å hente og lagre dataene mottatt av initialisatoren. I tillegg må du lagre maksimal tid som en spiller må svare på hvert spørsmål. Endre implementeringsfilen tilsvarende.

 @implementation FactsScene NSUserDefaults * standard; NSString * musicPath; NSInteger playerLives; NSInteger playerLevel; int maximumTime; 

Nå må du skrive initialisereren og lagre verdiene. Den tilpassede initialiseringen er definert som en normal initialiserer og har samme struktur. Det har imidlertid flere egenskaper som parametere. Det skal se slik ut:

 -(id) initWithSize: (CGSize) størrelse inLevel: (NSInteger) nivå medPlayerLives: (int) liv hvis (selv = [super initWithSize: size]) self.backgroundColor = [SKColor colorWithRed: 0.35 green: 0.25 blue: 0.5 alpha : 1,0]; standard = [NSUserDefaults standardUserDefaults]; playerLives = liv; playerLevel = level; maximumTime = 30;  returner selv; 

Steg 2

For nå, den maximumTime er 30 sekunder, men i fremtiden vil verdien endres til 60 sekunder (eller annen tid du ønsker). Nå i -(void) didMoveToView: (SKView *) visning Legg til et bakgrunnsbilde, frontbilde, spillerens liv, en tidtaker, sanne og falske knapper og nåværende og totalt nivå spørsmål. For bakgrunn og front bilde koden er enkel og du burde kunne gjøre det enkelt (bruk SKSpriteNode).

 SKSpriteNode * background = [SKSpriteNode spriteNodeWithImageNamed: @ "background.png"]; background.position = CGPointMake (CGRectGetMidX (self.frame), CGRectGetMidY (self.frame)); background.size = CGSizeMake (768, 1024); [self addChild: background]; SKSpriteNode * frontImage = [SKSpriteNode spriteNodeWithImageNamed: @ "transparentCenterBorder.png"]; frontImage.position = CGPointMake (CGRectGetMidX (self.frame), CGRectGetMidY (self.frame)); frontImage.size = CGSizeMake (600, 450); [self addChild: frontImage];

Spillerens liv er representert med et hjertebilde. Siden du vil erklære tre liv, må du sette tre hjerter på skjermen. Du vil også bruke en NSMutableArray siden vi må endre størrelsen dynamisk. Følgende utdrag vil hjelpe deg:

 heartArray = [[NSMutableArray alloc] init]; for (NSInteger i = 0; i < playerLives; i++) SKSpriteNode* liveImage = [SKSpriteNode spriteNodeWithImageNamed:@"hearth.png"]; liveImage.scale = .6; liveImage.position = CGPointMake(CGRectGetMaxX(self.frame)-40-(i*50),CGRectGetMaxY(self.frame)-40); [heartArray insertObject:liveImage atIndex:i]; [self addChild:liveImage]; 

De sanne og falske knappene er konfigurert som:

 _trueButton = [UIButton buttonWithType: UIButtonTypeRoundedRect]; _trueButton.frame = CGRectMake (CGRectGetMidX (self.frame) -350, CGRectGetMidY (self.frame) +300, 335, 106); _trueButton.backgroundColor = [UIColor clearColor]; [_trueButton setTitleColor: [UIColor whiteColor] forState: UIControlStateNormal]; UIImage * buttonTrueImageNormal = [UIImage imageNamed: @ "trueBtn.png"]; UIImage * strechableButtonTrueImageNormal = [buttonTrueImageNormal stretchableImageWithLeftCapWidth: 12 topCapHeight: 0]; [_trueButton setBackgroundImage: strechableButtonTrueImageNormal forState: UIControlStateNormal]; [_trueButton addTarget: selvhandling: @selector (touchWillProduceASound) forControlEvents: UIControlEventTouchUpInside]; [self.view addSubview: _trueButton]; _falseButton = [UIButton buttonWithType: UIButtonTypeRoundedRect]; _falseButton.frame = CGRectMake (CGRectGetMidX (self.frame) +10, CGRectGetMidY (self.frame) +300, 335, 106); _falseButton.backgroundColor = [UIColor clearColor]; [_falseButton setTitleColor: [UIColor whiteColor] forState: UIControlStateNormal]; UIImage * buttonFalseImageNormal = [UIImage imageNamed: @ "falseBtn.png"]; UIImage * strechableButtonFalseImageNormal = [buttonFalseImageNormal stretchableImageWithLeftCapWidth: 12 topCapHeight: 0]; [_falseButton setBackgroundImage: strechableButtonFalseImageNormal forState: UIControlStateNormal]; [_falseButton addTarget: selvhandling: @selector (touchWillProduceASound) forControlEvents: UIControlEventTouchUpInside]; [self.view addSubview: _falseButton];

Merk at begge knappene ringer til touchWillProduceASound metode. Denne metoden tester om et gitt svar er riktig eller feil. I denne delen bruker vi bare en lydhendelse (den falske).

 -(void) touchWillProduceASound long soundFlag = [standard integerForKey: @ "sound"]; NSString * answer = @ "False"; if (soundFlag == 1) SKAction * lyd; hvis ([svar isEqualToString: @ "False"]) lyd = [SKAction playSoundFileNamed: @ "wrong.mp3" waitForCompletion: YES]; NSLog (@ "innsiden");  [self runAction: lyd]; 

Trinn 3

Spilltimeren er a SKLabelNode som endres i hvert sekund. Imidlertid er initieringen gjort som en enkel SKLabelNode:

 _timerLevel = [SKLabelNode labelNodeWithFontNamed: @ "Chalkduster"]; _timerLevel.text = @ "30"; _timerLevel.fontSize = 70; _timerLevel.position = CGPointMake (CGRectGetMidX (self.frame), CGRectGetMidY (self.frame) +350); [self addChild: _timerLevel];

For å oppdatere etiketten må du opprette en SKAction som definerer en egendefinert timer for å ringe en tilpasset metode. Da må vi opprette en SKAction sekvens:

 SKAction * wait = [SKAction waitForDuration: 1]; SKAction * updateTimer = [SKAction runBlock: ^ [self updateTimer]; ]; SKAction * updateTimerS = [SKAction sekvens: @ [vent, updateTimer]]; [self runAction: [SKAction repeatActionForever: updateTimerS]];

Du vil se en advarsel om - (Void) updateTimer metode fordi du ikke har opprettet den enda. Den metoden tar flere tiltak samtidig i betraktning flere egenskaper:

  • Kontrollerer om lyden er på
  • Oppdaterer maximumTime eiendom og etikett, reduserer med en verdi hvert sekund
  • Kontrollerer maximumTime, og hvis verdien er null, vil den enten avslutte spillet eller bytte til et annet spørsmål (mer om dette emnet i neste opplæring)

Vi anbefaler deg å prøve å skrive metoden ved hjelp av den nevnte pseudokoden. Men hvis du har problemer, presenteres hele metoden nedenfor:

 - (ugyldig) updateTimer maximumTime--; hvis (maximumTime == 0) lang lydFlag = [standard integerForKey: @ "lyd"]; if (soundFlag == 1) SKAction * lyd; lyd = [SKAction playSoundFileNamed: @ "beep.mp3" waitForCompletion: YES]; [self runAction: lyd];  hvis (playerLives < 1) SKTransition* transition = [SKTransition fadeWithDuration:2]; MyScene* myscene = [[MyScene alloc] initWithSize:CGSizeMake(CGRectGetMaxX(self.frame), CGRectGetMaxY(self.frame))]; [self removeUIViews]; [self.scene.view presentScene:myscene transition:transition];  else // other   [_timerLevel setText:[[NSNumber numberWithInt:maximumTime] stringValue]]; 

Trinn 4

En annen metode mangler, den removeUIViews. Det fjerner UIKit visninger fra visningen når en overgang skjer.

 -(void) removeUIViews [_trueButton removeFromSuperview]; [_falseButton removeFromSuperview]; 

Det er nå tid til Løpe prosjektet og se fakta skjermen!

Illustrasjon av fakta skjermen

3. Eiendomslister

Nå er det på tide å legge til noen data i appen. Gå til Fil -> Ny -> Fil og velg Property List (plist) -filen. Gi det navnet "LevelDescription" og konfigurer det som følger:

Illustrasjon av eiendomslisten

For å unngå å sette alle dataene i plistfilen, kan du laste ned filen direkte på zip-filen (begynnelsen av siden). Denne opplæringen dekker ikke dataoppdateringen i dybden, så følgende deluttak brukes for å analysere den filen. Hvis du er i tvil, bruk kommentarboksen nederst på siden.

 NSString * plistPath = [[NSBundle mainBundle] pathForResource: @ "LevelDescription" ofType: @ "plist"]; NSMutableDictionary * ordbok = [[NSMutableDictionary alloc] initWithContentsOfFile: plistPath]; hvis ([ordbok objektForKey: @ "Spørsmål"]! = null) NSMutableArray * array = [ordbok objektForKey: @ "Spørsmål"]; for (int i = 0; i < [array count]; i++) NSMutableDictionary *questions = [array objectAtIndex:i]; NSLog(@"ID %@", [questions objectForKey:@"id"]); NSLog(@"%@", [questions objectForKey:@"statement"]); NSLog(@"%@", [questions objectForKey:@"isCorrect"]); NSLog(@"%@", [questions objectForKey:@"additionalInfo"]);  

Nå, Løpe prosjektet og se på konsollloggene når du går inn i faktavisningen. Merk at plistfilen kan konfigureres på flere forskjellige måter. Hvis du vil, kan du endre Ordbok, Array typer og konfigurasjoner. Vær oppmerksom på at endringer må deklareres i analyseprosessen. Vi anbefaler på det sterkeste at du spiller litt med plistfil og den innebygde dataanalysen.


Konklusjon

På dette punktet bør du kunne bruke og konfigurere en UITableView, samhandle mellom SpriteKit og UIKit-rammer, lage SKTransitions og SKActions, og opprett og analyser Property files. I den siste delen av denne serien lærer du om spilllogikk.