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.
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:
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.
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 moveToHome
metode 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];
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:
-(NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) seksjon
-(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;
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:
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;
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];
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:
maximumTime
eiendom og etikett, reduserer med en verdi hvert sekundmaximumTime
, 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]];
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!
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:
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.
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.