Ce tutoriel va vous apprendre à utiliser le framework Sprite Kit pour créer un jeu de faits basé sur des questions. Il est conçu pour les utilisateurs novices et avancés. En cours de route, vous appliquerez le noyau du kit Sprite. Les didacticiels du jeu de faits sont divisés en trois parties afin de couvrir complètement chaque section. Après ce didacticiel en trois parties, les lecteurs pourront créer un simple jeu de questions / réponses comportant des sons, des animations, des menus, des règles, des minuteries et une interaction UIKit..
Cette série est divisée en trois parties: Configuration du projet, Création d'interface et Logique de jeu. Chaque partie produira un résultat pratique et la somme de toutes les parties produira le jeu final. Bien que chaque partie puisse être lue indépendamment, pour une meilleure compréhension et orientation, nous suggérons que le tutoriel soit suivi pas à pas. Nous avons également inclus le code source de chaque partie séparément. Ainsi, fournir un moyen de démarrer le tutoriel dans n’importe quelle partie de la série.
Ceci est la deuxième partie de notre série de didacticiels Jeu de faits avec Sprite Kit. Dans ce tutoriel, vous allez programmer la sélection de niveau et l’interface principale de la scène de jeu. Ce tutoriel se concentre sur plusieurs aspects tels que, la personnalisation UITableView
, initialiseurs de classes personnalisées, listes de propriétés et SKActions
. Nous expliquerons tout plus loin ci-dessous. Si vous n'avez pas encore terminé la première partie de la série, vous pouvez télécharger le projet et le ramasser exactement à l'endroit où nous nous sommes arrêtés..
Voici à quoi ressemblera notre résultat final:
L'objectif principal de ce jeu est de créer plusieurs questions divisées par plusieurs niveaux. De cette façon, vous devez créer une interface personnalisée pour choisir le niveau auquel vous voulez jouer. Pour ce faire, vous devez ajouter un autre Objectif c
classe (Fichier -> Nouveau -> Fichier
). Nomme le LevelSelect
et choisissez le SKScene
comme la superclasse. Vous verrez deux nouveaux fichiers dans votre projet.
Pour la sélection du niveau, vous utiliserez le UITableView
visualisez-le et configurez-le avec plusieurs propriétés. En outre, vous devez également nommer les niveaux et leurs descriptions. dans le LevelSelect.h
vous devriez ajouter ces propriétés. L'extrait suivant vous aidera:
@property (nonatomic, keep) UIButton * backButton; @property (keep, nonatomic) IBOutlet UITableView * tableView; @property (strong, nonatomic) NSArray * levelsArray; @property (strong, nonatomic) NSArray * levelsDescriptionArray;
L'extrait contient également un UIButton
appelé backButton. A ce moment, le bouton est explicite. il aide l'utilisateur à revenir de l'interface de sélection de niveau à l'interface principale.
Ensuite, concentrez-vous sur LevelSelect.m
. La première étape consiste à ajouter le -(id) initWithSize: taille (CGSize)
méthode. Dans cette classe, vous ne configurerez que la couleur d'arrière-plan. Vous pouvez choisir la couleur que vous aimez le plus.
-(id) initWithSize: (CGSize) taille if (self = [super initWithSize: size]) self.backgroundColor = [SKColor couleurWithRed: 0,25 vert: 0,35 bleu: 0,15 alpha: 1,0]; retourner soi-même;
Depuis que vous utilisez UIKit
vues, vous devez ajouter le -(void) didMoveToView: (SKView *) voir
méthode. Cette méthode définit et configure le backButton et le tableView, place un libellé de titre pour la vue, alloue et initialise le levelsArray et le levelsDescriptionArray et ajoute le tableView à la vue principale. le bouton de retour
peut être configuré comme suit:
_backButton = [UIButton buttonWithType: UIButtonTypeRoundedRect]; _backButton.frame = CGRectMake (CGRectGetMidX (self.frame) -100, CGRectGetMaxY (self.frame) -100, 200, 70.0); _backButton.backgroundColor = [UIColor clearColor]; [_backButton setTitleColor: [WhiteColor UIColor] pourState: UIControlStateNormal]; UIImage * buttonExitImageNormal = [UIImage imageNamed: @ "back.png"]; UIImage * strechableButtonExitImageNormal = [buttonExitImageNormal stretchableImageWithLeftCapWidth: 12 topCapHeight: 0]; [_backButton setBackgroundImage: strechableButtonExitImageNormal forState: UIControlStateNormal]; [_backButton addTarget: action propre: @selector (moveToHome) forControlEvents: UIControlEventTouchUpInside]; [self.view addSubview: _backButton];
De plus, vous devez créer le moveToHome
méthode et importation
la MyScene.h
.
-(void) moveToHome MyScene * myScene = [[MyScene alloc] initWithSize: CGSizeMake (CGRectGetMaxX (self.frame), CGRectGetMaxY (self.frame))]; [auto removeUIViews]; [self.scene.view presentScene: myScene];
Puisque vous devez enlever UIKIt
vues à plus d'un endroit, créons une méthode qui fait exactement cela. La méthode s'appelle supprimerUIViews
et est montré ci-dessous:
-(void) removeUIViews [_backButton removeFromSuperview]; [_tableView removeFromSuperview];
Le libellé de cette interface est très simple. Essayez de le programmer vous-même. Si vous avez des problèmes, l'extrait suivant vous aidera.
SKLabelNode * titleLabel = [SKLabelNode labelNodeWithFontNamed: @ "Chalkduster"]; titleLabel.text = @ "Sélection du niveau !!"; titleLabel.fontSize = 60; titleLabel.position = CGPointMake (CGRectGetMidX (self.frame), CGRectGetMidY (self.frame) +300); [auto addChild: titleLabel];
le tableView
la configuration est un peu délicate car nous devons configurer plusieurs propriétés, telles que la taille et l'emplacement du cadre, la source de données et un délégué.
_tableView = [[UITableView alloc] initWithFrame: CGRectMake (CGRectGetMidX (self.frame) -150, CGRectGetMidY (self.frame) -250, 300, 400)]; _tableView.dataSource = self; _tableView.delegate = self;
Les deuxième et troisième lignes de l'extrait de code susmentionné nécessitent une étape supplémentaire, car vous définissez simultanément deux vues. La source de données du UITableView
est auto-défini et le UITableView
a un délégué d'action. Dans LevelSelect.h
vous devriez prolonger votre classe avec UITableViewDataSource
et UITableViewDelegate
. Votre LevelSelect.h
devrait ressembler à:
@interface LevelSelect: SKScene < UITableViewDataSource, UITableViewDelegate >
Puisque vous prolongez le UITableViewDataSource
et UITableViewDelegate
, des méthodes supplémentaires doivent être mises en œuvre, à savoir:
-(NSInteger) tableView: (UITableView *) table numéro de sectionOfRowsInSection: (NSInteger) section
-(UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath
Le premier sert uniquement à connaître en temps réel le nombre de lignes existant dans la vue tableau. La seconde méthode est complexe car elle permet de renseigner et de configurer la vue tableau. La configuration de la vue table couvre le titre, la description et une image de ligne. Pour utiliser la description dans chaque ligne, nous devons initialiser chaque cellule avec le UITableViewCellStyleSubtitle
style de cellule.
Cette méthode est responsable d’une étape supplémentaire: elle vérifie le niveau du joueur actuel et désactive les niveaux en avant de la actualPlayerLevel
. La déclaration complète des méthodes est visible ci-dessous:
-(UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath NSString * levels = [_levelsArray objectAtIndex: indexPath.row]; NSString * descriptions = [_levelsDescriptionArray objectAtIndex: indexPath.row]; UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: @ "identificateur"]; if (cell == nil) cell = [[UITableViewCell alloc]] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: @ "Identificateur"]; if (indexPath.row> = actualPlayerLevel) [cellule setUserInteractionEnabled: FALSE]; [cell.textLabel setText: levels]; cell.imageView.image = [UIImage imageNamed: @ "appleLogo.png"]; [cell.detailTextLabel setText: descriptions]; cellule de retour;
-(NSInteger) tableView: (UITableView *) numéro de la table (numéro de la vue): (NSInteger) section return [_levelsArray count];
Voici deux notes concernant la -(UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath
méthode. Vous n'avez pas encore initialisé les propriétés levelsArray, levelsDescriptionArray et actualPlayerLevel. Tout sera défini dans le -(void) didMoveToView: (SKView *) voir
méthode. N'oubliez pas d'ajouter le actualPlayerLevel
propriété à votre classe:
@implementation LevelSelect long actualPlayerLevel;
le niveauxArray
est défini avec les noms des niveaux. Vous pouvez l'appeler "Niveau 1", "Niveau 2" ou tout autre nom de votre choix. le niveauxDescriptionArray
suit le même principe, il s'agit d'une description pour chaque niveau et peut être défini avec les noms de votre choix. Une implémentation possible est:
_levelsArray = [[NSArray alloc] initWithObjects: @ "niveau 1.", @ "niveau 2.", @ "niveau 3.", @ "niveau 4", @ "niveau 5", @ "niveau 6". , @ "Niveau 7.", @ "Niveau 8.", @ "Niveau 9.", Nul]; _levelsDescriptionArray = [[NSArray alloc] initWithObjects: @ "L'aventure commence.", @ "Une nouvelle étape.", @ "Réalisations?!", @ "Description du niveau 4", @ "Description du niveau 5", @ "Niveau 6 description ", @" description du niveau 7 ", @" description du niveau 8 ", @" description du niveau 9 ", nil];
Finalement, le actualPlayerLevel
est un longue
type de valeur qui représente le niveau du joueur. Pour le moment, disons que le niveau actuel est 1.
actualPlayerLevel = 1;
le -(void) didMoveToView: (SKView *) voir
méthode se termine lorsque vous ajoutez la vue tabulaire à l'écran:
[self.view addSubview: _tableView];
Enfin, vous avez besoin d’un changement supplémentaire dans la MyScene.m
-(void) moveToGame
méthode. Vous devez appeler cette nouvelle classe à la place de l'ancienne. Cela peut être facilement réalisé par:
-(void) moveToGame LevelSelect * factsScene = [[LevelSelect alloc]] initWithSize: CGSizeMake (CGRectGetMaxX (self.frame), CGRectGetMaxY (self.frame))]; // Même code //…
À ce stade, vous devriez Courir
le projet et tester la nouvelle interface. Vous devriez voir quelque chose de similaire à l'image suivante:
L'interface des faits est l'endroit où se produit l'action réelle. L'interface comporte plusieurs vues qui se traduisent directement en propriétés, telles que le nombre de vies restantes, le niveau actuel, une minuterie et les boutons true et false. De plus, pour cette classe, vous allez créer un initialiseur personnalisé. L'avantage de cet initialiseur personnalisé est que nous pouvons progresser dans le jeu et les valeurs relatives au niveau. De plus, les vies sont transmises à la classe et celle-ci réagit (analyse les données) en conséquence..
Encore une fois, nous allons utiliser SKLabelNode
, UIButtons
, et un NSMutableArray
. Le complet FactsScene.h
est le suivant:
@interface FactsScene: SKScene NSMutableArray * heartArray; @property (nonatomic, faible) SKLabelNode * currentLevelLabel; @property (nonatomic, faible) SKLabelNode * timerLevel; @property (nonatomic, keep) UIButton * trueButton; @property (nonatomic, keep) UIButton * falseButton; - (id) initWithSize: (CGSize) size inLevel: (NSInteger) niveau avecPlayerLives: (int) lives;
Il est maintenant temps de passer à la FactsScene.m
et implémenter quelques objets. Vous avez besoin d'objets supplémentaires pour récupérer et stocker les données reçues par l'initialiseur. De plus, vous devez enregistrer le temps maximum qu'un joueur a pour répondre à chaque question. Modifier le fichier d'implémentation en conséquence.
@implementation FactsScene NSUserDefaults * defaults; NSString * musicPath; NSInteger playerLives; NSInteger playerLevel; int maximumTime;
Maintenant, vous devez écrire l'initialiseur et stocker ses valeurs. L'initialiseur personnalisé est défini comme un initialiseur normal et a la même structure. Cependant, il a plus de propriétés en tant que paramètres. Ça devrait ressembler à ça:
-(id) initWithSize: (CGSize) size inLevel: (NSInteger) niveau avecPlayerLives: (int) lives if (self = [super initWithSize: size]) self.backgroundColor = [SKColor colorWithRed: 0.35 vert: 0.25 vert: 0.25 bleu: 0.5 alpha : 1,0]; defaults = [NSUserDefaults standardUserDefaults]; playerLives = vies; playerLevel = level; maximumTime = 30; retourner soi-même;
Pour l'instant, le durée maximale
est 30 secondes, mais à l'avenir, la valeur passera à 60 secondes (ou à tout autre moment de votre choix). Maintenant dans le -(void) didMoveToView: (SKView *) voir
ajoutez une image d'arrière-plan, une image avant, la vie du joueur, une minuterie, des boutons Vrai et Faux, et les questions du niveau actuel et total Pour le Contexte
et de face
image le code est simple et vous devriez pouvoir le faire facilement (en utilisant SKSpriteNode
).
SKSpriteNode * background = [SKSpriteNode spriteNodeWithImageNamed: @ "background.png"]; background.position = CGPointMake (CGRectGetMidX (self.frame), CGRectGetMidY (self.frame)); background.size = CGSizeMake (768, 1024); [auto addChild: background]; SKSpriteNode * frontImage = [SKSpriteNode spriteNodeWithImageNamed: @ "transparentCenterBorder.png"]; frontImage.position = CGPointMake (CGRectGetMidX (self.frame), CGRectGetMidY (self.frame)); frontImage.size = CGSizeMake (600, 450); [auto addChild: frontImage];
Les vies du joueur sont représentées avec une image de coeur. Puisque tu vas déclarer trois vies, tu dois mettre trois coeurs à l'écran. Vous utiliserez également un NSMutableArray
puisque nous devons modifier sa taille de manière dynamique. L'extrait suivant vous aidera:
heartArray = [[NSMutableArray alloc] init]; pour (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];
Les boutons true et false sont configurés comme suit:
_trueButton = [UIButton buttonWithType: UIButtonTypeRoundedRect]; _trueButton.frame = CGRectMake (CGRectGetMidX (self.frame) -350, CGRectGetMidY (self.frame) +300, 335, 106); _trueButton.backgroundColor = [UIColor clearColor]; [_trueButton setTitleColor: [WhiteColor UIColor] pourState: UIControlStateNormal]; UIImage * buttonTrueImageNormal = [UIImage imageNamed: @ "trueBtn.png"]; UIImage * strechableButtonTrueImageNormal = [buttonTrueImageNormal stretchableImageWithLeftCapWidth: 12 topCapHeight: 0]; [_trueButton setBackgroundImage: strechableButtonTrueImageNormal forState: UIControlStateNormal]; [_trueButton addTarget: action propre: @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] pourState: UIControlStateNormal]; UIImage * buttonFalseImageNormal = [UIImage imageNamed: @ "falseBtn.png"]; UIImage * strechableButtonFalseImageNormal = [buttonFalseImageNormal stretchableImageWithLeftCapWidth: 12 topCapHeight: 0]; [_falseButton setBackgroundImage: strechableButtonFalseImageNormal forState: UIControlStateNormal]; [_falseButton addTarget: action propre: @selector (touchWillProduceASound) forControlEvents: UIControlEventTouchUpInside]; [self.view addSubview: _falseButton];
Notez que les deux boutons appellent le touchWillProduceASound
méthode. Cette méthode teste si une réponse donnée est correcte ou incorrecte. Dans cette partie, nous n'utilisons qu'un seul événement sonore (le faux).
-(void) touchWillProduceASound long soundFlag = [defaults integerForKey: @ "sound"]; NSString * answer = @ "False"; if (soundFlag == 1) SKAction * sound; if ([answer isEqualToString: @ "False"]) sound = [SKAction playSoundFileNamed: @ "wrong.mp3" waitForCompletion: YES]; NSLog (@ "inside"); [self runAction: sound];
Le chronomètre est un SKLabelNode
cela change à chaque seconde. Cependant, son initialisation se fait comme un simple SKLabelNode
:
_timerLevel = [SKLabelNode labelNodeWithFontNamed: @ "Chalkduster"]; _timerLevel.text = @ "30"; _timerLevel.fontSize = 70; _timerLevel.position = CGPointMake (CGRectGetMidX (self.frame), CGRectGetMidY (self.frame) +350); [auto addChild: _timerLevel];
Pour mettre à jour l’étiquette, vous devez créer un SKAction
qui définit une minuterie personnalisée pour appeler une méthode personnalisée. Ensuite, nous devons créer un SKAction
séquence:
SKAction * wait = [SKAction waitForDuration: 1]; SKAction * updateTimer = [SKAction runBlock: ^ [self updateTimer]; ]; SKAction * updateTimerS = [séquence SKAction: @ [wait, updateTimer]]; [self runAction: [SKAction repeatActionForever: updateTimerS]];
Vous verrez un avertissement concernant la - (void) updateTimer
méthode parce que vous ne l'avez pas encore créé. Cette méthode effectue plusieurs actions simultanément en prenant en compte plusieurs propriétés:
durée maximale
property et Label, diminuant d'une valeur chaque secondedurée maximale
, et si la valeur est zéro, cela mettra fin au jeu ou changera pour une autre question (plus à ce sujet dans le prochain tutoriel)Nous vous conseillons d'essayer d'écrire la méthode en utilisant le pseudo-code susmentionné. Mais si vous avez des problèmes, la méthode complète est présentée ci-dessous:
- (void) updateTimer maximumTime--; if (maximumTime == 0) long soundFlag = [défaut par défaut integerForKey: @ "sound"]; if (soundFlag == 1) SKAction * sound; sound = [SKAction playSoundFileNamed: @ "beep.mp3" waitForCompletion: YES]; [self runAction: sound]; if (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]];
Une autre méthode manque, la supprimerUIViews
. Ça enlève le UIKit
vues de la vue quand une transition se produit.
-(void) removeUIViews [_trueButton removeFromSuperview]; [_falseButton removeFromSuperview];
Il est maintenant temps de Courir
le projet et voir l'écran des faits!
Il est maintenant temps d'ajouter des données à l'application. Aller à Fichier -> Nouveau -> Fichier
et choisissez le fichier Property List (plist). Nommez-le "LevelDescription" et configurez-le comme suit:
Afin d'éviter de mettre toutes les données dans le fichier plist, vous pouvez télécharger le fichier directement sur le fichier zip (début de la page). Ce tutoriel ne couvre pas en profondeur l'analyse des données. Par conséquent, pour analyser ce fichier, l'extrait de code suivant est utilisé. Si vous avez des doutes, utilisez la zone de commentaire au bas de la page..
NSString * plistPath = [[NSBundle mainBundle] pathForResource: @ "LevelDescription" ofType: @ "plist"]; NSMutableDictionary * dictionary = [[NSMutableDictionary alloc] initWithContentsOfFile: plistPath]; if ([dictionnaire objectForKey: @ "Questions"]! = nil) NSMutableArray * array = [dictionnaire objectForKey: @ "Questions"]; pour (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"]);
À présent, Courir
le projet et observez les journaux de la console lorsque vous accédez à la vue Faits. Notez que le fichier plist peut être configuré de différentes manières. Si vous voulez, vous pouvez changer le dictionnaire
, Tableau
types et configurations. Notez que les modifications doivent être déclarées dans le cycle d'analyse. Nous vous conseillons vivement de jouer un peu avec le fichier plists et l’analyse de données inhérente.
À ce stade, vous devriez pouvoir utiliser et configurer un UITableView, interagir entre les frameworks SpriteKit et UIKit, créer SKTransitions et SKActions et créer et analyser des fichiers de propriétés. Dans la dernière section de cette série, vous découvrirez Game Logic..