Au jour d’aujourd’hui, les jeux vidéos sont de plus en plus présent. Avec l’univers du smartphone, il est de plus en plus facile d’embarquer des jeux vidéos avec nous et ce partout.

Plusieurs jeux ont eu un tel succès qu’il reste difficile d’ignorer cet utilisation de nos téléphones en tant que console. A n’en citer que quelques-uns: DoodleJump, AngryBird ou encore le fameux CandyCrush.

Depuis la sortie d’iOS7, Apple a rajouté un framework de jeu vidéo 2D directement dans son SDK: SpriteKit. Nous allons voir ensemble comment l’utiliser.

Mise en place:

SpriteKit ne nécessite pas d’installation particulière, soit vous commencez avec un projet de type “SpriteKit Game” déjà proposé:

Soit vous l’ajoutez à un projet existant, directement avec le lien de la librairie:

Utilisation:

On garde l’architecture classique d’un “viewController” comprenant une “view”. La différence ici est que cette “view” sera d’un type différent: une SKView, héritée directement de la classe UIView. Le reste des élements graphiques se définissent comme des “nodes” (SKLabelNode, SKShapeNode, etc).

De là, plusieurs questions viennent à nous:

  • Qu’est qui change? SKView gère l’affichage d’éléments SpriteKit.
  • Que va-t-on présenter dans notre fameuse SKView? On va lui demander de présenter l’élément racine du contenu SpriteKit: une SKScene. Elle nous permettra l’affichage du rendu définitif (images, animations, actions, etc.).

En somme, voila ce que ça donne au niveau du code:

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Configure the view.
    SKView * skView = (SKView *)self.view;
    skView.showsFPS = YES; // affiche les FPS pour suivre le taux de rafraichissement
    skView.showsNodeCount = YES; // affiche le compteur de node (elements)

    // Create and configure the scene.
    SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];
    scene.scaleMode = SKSceneScaleModeAspectFill;

    // Present the scene.
    [skView presentScene:scene];
}

Tout ça nous charge notre fameuse scène dans notre vue. La suite est simple, on charge nos différents éléments dans notre scène, comme on l’aurait fait sur notre UIView, à la différence près qu’on les associe à notre SKScene comme des enfants (“child”).

@implementation MyScene

-(id)initWithSize:(CGSize)size {
    if (self = [super initWithSize:size]) {
        /* Setup your scene here */

        /* SKColor => UIColor or NSColor */
        self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];

        /* SKLabelNode => UILabel */
        SKLabelNode *myLabel = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];

        myLabel.text = @"Hello, World!";
        myLabel.fontSize = 30;
        myLabel.position = CGPointMake(CGRectGetMidX(self.frame),
                                       CGRectGetMidY(self.frame));

        [self addChild:myLabel];
    }
    return self;
}

Voici le rendu:

A savoir en plus:

L’origine des axes (X,Y) n’est plus le même entre UIView et SKView: on ne part plus du point en haut à gauche, mais du point en bas à gauche.

Origine coordonnees SKView

Origine Coordonnees UIView

Ce que ça change pour nous, c’est que si nous écoutons des actions via l’UIViewController de départ (et des “UIGestureRecognizer” dans “Interface Builder”), il faudra traduire les coordonnées pour notre SKView.

Evidemment, chaque SKNode réagit pareil que SKView, donc si vous avez des SKNode imbriqués, il faudra à chaque fois traduire le point d’entré (CGPoint) de l’UIView au SKView, puis du SKView au SKNode enfant: comme la descendance UIView, à chaque enfant l’origine X,Y est remise à 0 par rapport à l’objet.

Si on reprend l’exemple de notre SKLabelNode, si nous lui ajoutons un enfant, la SKNode ajoutée se basera sur l’origine du SKLabelNode et non du SKScene (grand parent pour le coup).

Des animations

Element sympathique de SpriteKit, on peut ajouter des actions (SKAction plus précisemment) à des nodes, afin de les animer. Encore plus intéressant, on peut leur donner un groupe d’action à executer ou des séquences. Le groupe execute les actions toutes en même temps, la séquence joue une action après l’autre.

- (void)actionOnSKLabelNode:(SKLabelNode *)label
{
    SKAction *fadeInAction = [SKAction fadeInWithDuration:1.0];
    SKAction *fadeOutAction = [SKAction fadeOutWithDuration:1.0];

    SKAction *sequence = [SKAction sequence:@[fadeInAction, fadeOutAction]];
    [label runAction:sequence];
}

Notre code ici nous permet, à l’envoie du message “actionOnSKLabelNode:” de faire apparaitre puis disparaitre notre label.

On a un maximum d’actions pour un maximum d’animations. Cela nous laisse beaucoup de possibilités pour notre création de jeu. Pour plus d’informations, voici la documentation SKAction.

Conclusion:

J’avais déjà travaillé avec Sparrow, un framework open source pour jeux vidéos 2D, et pour le coup, je préfère SpriteKit. Le debug ainsi que le monitoring du rendu me semble plus facile. Je ne suis pas allé loin dans le concept du jeu vidéo, mais SpriteKit reste simple d’utilisation, s’il faut trouver un regret c’est qu’il n’ait pas prévu l’aspect “musique de jeu” dans leur framework.