• 20 heures
  • {0} Facile|{1} Moyenne|{2} Difficile

Ce cours est visible gratuitement en ligne.

Ce cours existe en livre papier.

J'ai tout compris !

Mis à jour le 21/06/2013

Un jeu de casse briques

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Dans ce chapitre, vous allez apprendre à créer un jeu de casse-briques. Ce classique du genre va vous montrer de nombreuses techniques propres aux jeux et ainsi vous préparer pour le prochain chapitre, qui sera un TP sur la création d'un autre jeu. Mais revenons à ce chapitre.

Vous apprendrez entre autres à :

  • définir et animer des objets animés ;

  • détecter des collisions ;

  • effectuer des boucles de traitement ;

  • utiliser une musique de fond ;

  • utiliser des bruitages.

J'espère vous avoir mis l'eau à la bouche. Passez vite à la suite et commençons sans attendre !

Avant toute chose, je vais vous montrer à quoi va ressembler l'application que nous allons réaliser. Pour cela, regardez la figure suivante. J'espère qu'elle vous plaît.

Le casse-briques que nous allons réaliser
Le casse-briques que nous allons réaliser

Définition de l'interface

Lancez Xcode, définissez un nouveau projet de type Single View Application et donnez-lui le nom « pong » (C'est moins long que « casse-briques » mais tout aussi parlant pour notre application.).

Ce jeu va utiliser plusieurs éléments graphiques :

  • une image d'arrière-plan de 320x480 pixels ;

  • une image PNG d'une brique de 70x15 pixels ;

  • une image PNG d'une raquette de 70x15 pixels ;

  • une image PNG d'une balle de 16x16 pixels.

L'arrière-plan est une quelconque image enregistrée au format JPG ou PNG et de dimensions bien précises : 320x480 pixels.
Les briques, la raquette et la balle sont au format PNG. Vous pouvez créer vous-mêmes vos images, mais au cas où, vous pouvez télécharger celles que j'ai utilisées dans ce chapitre.

Pour accéder facilement à ces éléments graphiques, vous allez les placer dans les ressources de l'application. Cliquez du bouton droit sur la première icône du volet de navigation et sélectionnez New group dans le menu contextuel. Renommez le nouveau dossier « Resources ». Maintenez le bouton gauche de la souris enfoncé et glissez-déposez les fichiers background.png, brique.png, raquette.png et balle.png depuis le Finder dans le dossier Resources de l'application. Au relâchement du bouton gauche de la souris, une boîte de dialogue est affichée. Assurez-vous que la case Copy items into destination group's folder (if needed) est cochée, puis cliquez sur Finish. Votre arborescence devrait ressembler à la figure suivante.

L'arborescence de votre application devrait ressembler à celle-ci

Vous allez maintenant créer l'interface du jeu avec Interface Builder.

Cliquez sur MainStoryboard.storyboard dans le volet de navigation et affichez si nécessaire le volet des utilitaires en cliquant sur l'icône Hide or Show the Utilities dans la barre d'outils. Vous allez maintenant déposer neuf contrôles UIImageView (oui, vous avez bien lu !) depuis la bibliothèque d'objets sur la vue de l'application.

À quoi vont servir tous ces objets ? Est-ce qu'ils sont vraiment tous nécessaires ?

Eh bien oui, tous ces objets sont nécessaires : sept vont représenter les briques, un la raquette et le dernier la balle.

Je vais vous montrer comment procéder pour un de ces objets, une brique en l'occurrence. En utilisant la même technique, vous n'aurez aucun mal à définir et positionner les autres objets. Pour ajouter une brique, suivez les étapes ci-après.

  1. Glissez-déposez un contrôle UIImageView sur la feuille de l'application.

  2. Cliquez sur l'icône Show the Attributes inspector dans le volet des utilitaires. Déroulez la liste Image et choisissez « brique.png ».

  3. Cliquez sur l'icône Show the Size inspector et modifiez les dimensions de la brique : « 70 » dans la case Width et « 15 » dans la case Height (c'est la taille de notre brique), comme indiqué à la figure suivante.

  4. Déplacez la brique dans la partie supérieure de la vue.

Modifiez la taille de la brique

Ajoutez puis déplacez les huit objets restant pour obtenir quelque chose ressemblant à la figure suivante.

Disposez les briques comme ceci

Pour en terminer avec l'interface de l'application, vous allez ajouter un contrôle Label. Ce contrôle sera utilisé pour afficher des informations textuelles du type « 3, 2, 1, partez… » lorsque le joueur perdra la balle.

Glissez-déposez un contrôle Label de la bibliothèque d'objets sur la vue. Redimensionnez ce contrôle pour qu'il occupe les trois quarts de la vue. Dans l'inspecteur des attributs, supprimez le contenu de la case Text pour que le Label n'affiche rien par défaut et choisissez une police System de 50 points, comme à la figure suivante.

Placez et paramétrez un Label

Liaison des contrôles au code

Pour pouvoir interagir avec ces contrôles, vous devez créer des outlets. Contrôle-glissez-déposez tour à tour chacun des objets de la vue sur le fichier d'en-têtes et créez les outlets brique1 à brique7, balle, raquette et stop3s (pour le contrôle Label). Une fois tous les outlets créés, le fichier d'en-têtes devrait ressembler à ceci :

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UIImageView *brique1;
@property (weak, nonatomic) IBOutlet UIImageView *brique2;
@property (weak, nonatomic) IBOutlet UIImageView *brique3;
@property (weak, nonatomic) IBOutlet UIImageView *brique4;
@property (weak, nonatomic) IBOutlet UIImageView *brique5;
@property (weak, nonatomic) IBOutlet UIImageView *brique6;
@property (weak, nonatomic) IBOutlet UIImageView *brique7;
@property (weak, nonatomic) IBOutlet UILabel *stop3s;
@property (weak, nonatomic) IBOutlet UIImageView *balle;
@property (weak, nonatomic) IBOutlet UIImageView *raquette;
@end

Immersion dans le code

Définition de l'arrière-plan de l'application

Vous allez maintenant commencer à écrire le code de l'application. La première étape va consister à définir l'image d'arrière-plan. Cliquez sur ViewController.m dans le volet de navigation et insérez l'instruction suivante au début de la méthode viewDidLoad :

self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"background.png"]];

Cette instruction a déjà été rencontrée à plusieurs reprises. Elle affecte une image d'arrière-plan (méthode backgroundColor) à la vue courante (self.view) en utilisant une image dans les ressources ([[UIColor alloc] initWithPatternImage:[UIImage imageNamed:). L'image utilisée a pour nom « background.png ». Libre à vous d'utiliser une quelconque autre image, pourvu que sa taille soit égale à 320x480 pixels.

Vous pouvez lancer l'application. Vous l'avez bien mérité. La figure suivante représente ce que vous devriez obtenir.

Les images de l'application s'affichent correctement

Déplacement de la balle

Avant de pouvoir jouer, plusieurs étapes sont nécessaires. Dans un premier temps, vous allez donner vie à la balle. Pour cela, vous allez devoir mettre en place un timer. Mais avant, retournez dans le fichier d'en-têtes et définissez la variable d'instance vitesseBalle comme suit :

@interface ViewController : UIViewController
{
CGPoint vitesseBalle;
}

La variable vitesseBalle est une structure CGPoint. Elle consiste en deux flottants qui définissent des coordonnées. Dans notre cas, nous utiliserons cette variable pour calculer l'endroit où la balle doit être affichée. La figure suivante vous montre ce que dit la documentation Apple sur la structure CGPoint.

La documentation Apple concernant CGPoint

Retournez dans le fichier ViewController.m et définissez la méthode boucleJeu comme suit :

-(void) boucleJeu
{
balle.center = CGPointMake(balle.center.x + vitesseBalle.x , balle.center.y + vitesseBalle.y);
if (balle.center.x > self.view.bounds.size.width || balle.center.x < 0)
vitesseBalle.x = -vitesseBalle.x;
if (balle.center.y > self.view.bounds.size.height || balle.center.y < 0)
vitesseBalle.y = -vitesseBalle.y;
}

Examinons les instructions utilisées dans cette méthode.

La ligne 3 calcule les prochaines coordonnées de la balle (balle.center). Ces coordonnées sont obtenues en ajoutant aux coordonnées actuelles (balle.center.x et balle.center.y) le déplacement désiré (vitesseBalle.x et vitesseBalle.y). Tout ce petit monde est passé à une instruction CGPointMake, qui retourne les nouvelles coordonnées de la balle (CHPointMake(…)). Pour que la balle se déplace, il suffit d'affecter le résultat de l'instruction CGPointMake à la propriété center de l'objet balle, c'est-à-dire au centre de la balle :

balle.center = CGPointMake(balle.center.x + vitesseBalle.x , balle.center.y + vitesseBalle.y);

L'instruction suivante s'intéresse à l'abscisse (la position horizontale) de la balle qui, rappelons-le, vient d'être calculée. Si cette abscisse est supérieure à la largeur de la vue (balle.center.x > self.view.bounds.size.width) ou si elle est négative (|| balle.center.x < 0), il suffit d'inverser la direction en X de la balle pour qu'elle ne sorte pas de la vue (vitesseBalle.x = -vitesseBalle.x;). Ce qui donne :

if (balle.center.x > self.view.bounds.size.width || balle.center.x < 0)
vitesseBalle.x = -vitesseBalle.x;

Examinez l'instruction suivante. Je suis sûr que vous y voyez quelques similitudes :

if (balle.center.y > self.view.bounds.size.height || balle.center.y < 0)
vitesseBalle.y = -vitesseBalle.y;

Ici, c'est l'ordonnée (la position verticale) qui est examinée. Si elle dépasse la hauteur de la vue (balle.center.y > self.view.bounds.size.height) ou si elle est négative (|| balle.center.y < 0), la direction en Y est inversée pour que la balle ne sorte pas de la vue (vitesseBalle.y = -vitesseBalle.y).

Tout cela est bien joli, mais dans quel sens va partir la balle ? Je crois bien que la direction de la balle n'a pas été définie au lancement de l'application.

Effectivement. Nous allons immédiatement réparer cette lacune en ajoutant l'instruction suivante dans la méthode viewDidLoad :

vitesseBalle = CGPointMake(10,15);

Cette instruction définit l'objet CGPoint vitesseBalle et affecte les valeurs 10 et 15 à ses composantes X et Y. Par la suite, nous utiliserons cet objet pour modifier les coordonnées de la balle… et donc la déplacer.

Je vous sens impatients de lancer l'application pour voir la balle se déplacer dans la vue. Je ne vais pas vous priver de ce plaisir. Cliquez sur Run et admirez… admirez… cette belle balle immobile au milieu de la vue !

Que se passe-t-il ? J'ai pourtant respecté à la lettre tout ce qui a été dit jusqu'ici !

Réfléchissez un peu. Vous avez défini une méthode pour animer la balle, mais croyez-vous que cette méthode va s'exécuter toute seule ? Bien sûr que non, il faut le lui demander en mettant en place un timer. Ajoutez l'instruction suivante dans la méthode viewDidLoad :

timer1 = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(boucleJeu) userInfo:nil repeats:YES];

Cette instruction définit l'objet timer1 (timer1 =) en utilisant un message Objective-C. Le message dit en substance ceci :

  • le code du timer doit être exécuté toutes les 0,05 seconde, soit 20 fois par seconde : [NSTimer scheduledTimerWithTimeInterval:0.05 ;

  • la méthode à exécuter se trouve dans la classe courante, c'est-à-dire celle du contrôleur de vue : target:self ;

  • la méthode à exécuter a pour nom boucleJeu : selector:@selector(boucleJeu) ;

  • aucune information complémentaire n'est passée à cette méthode : userInfo:nil ;

  • la méthode doit se répéter indéfiniment (ou du moins jusqu'à ce qu'il soit désactivé) : repeats:YES].

Pensez également à déclarer l'objet timer dans le fichier ViewController.h :

@interface ViewController : UIViewController
{
CGPoint vitesseBalle;
NSTimer *timer1;
}

Maintenant, vous pouvez lancer l'application et voir (oh merveille !) la balle se déplacer et rebondir sur les coins de l'écran (et votre doigt sur le device).

Déplacement de la raquette

Vous allez maintenant donner vie à la raquette et lui demander de suivre la souris dans le simulateur.

Définissez la méthode suivante dans le fichier ViewController.m (par exemple, juste après la méthode boucleJeu) :

-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
raquette.center = CGPointMake(location.x,raquette.center.y);
}

Examinons les instructions contenues dans cette méthode.
À la ligne 3, l'objet touch de classe UITouch est défini (UITouch *touch). Il est initialisé avec toutes les actions toucher de l'utilisateur (= [[event allTouches] anyObject];) :

UITouch *touch = [[event allTouches] anyObject];

La ligne 4 définit l'objet location de classe CGPoint (CGPoint location) et l'initialise avec la position du toucher (= [touch locationInView:touch.view];) :

CGPoint location = [touch locationInView:touch.view];

La variable location contient la position du doigt de l'utilisateur dans la vue. L'instruction de la ligne 5 affecte l'abscisse de cette position à celle de la raquette (raquette.center = CGPointMake(location.x, …). L'ordonnée de la raquette, quant à elle, ne doit pas suivre le doigt de l'utilisateur, mais rester sur une ligne horizontale (raquette.center.y) :

raquette.center = CGPointMake(location.x,raquette.center.y);

Lancez l'application en cliquant sur Run. La raquette doit maintenant suivre les mouvements de la souris, bouton gauche enfoncé. Quelle réussite !

Lisez vite la suite, vous allez découvrir comment détecter des collisions entre deux objets. Cela vous permettra de faire rebondir la balle sur la raquette et d'effacer les briques sur lesquelles rebondit la balle.

Détection des collisions

Comme nous l'avons vu précédemment, il est possible de connaître les coordonnées d'un objet en utilisant les propriétés center.x et center.y de cet objet. Par exemple, les coordonnées de la balle sont obtenues avec les expressions balle.center.x et balle.center.y.

Est-ce que vous savez comment détecter la collision entre deux objets ? En testant leurs coordonnées center.x et center.y bien entendu ! Encore plus fort : vous pouvez utiliser la méthode CGRectIntersectsRect pour tester la collision entre deux objets.

Voyons comment tester le contact de la balle sur la première brique. Ajoutez le test suivant dans la méthode boucleJeu :

if ((CGRectIntersectsRect(balle.frame,brique1.frame)) && (brique1.hidden == NO))
{
brique1.hidden=YES;
vitesseBalle.y = -vitesseBalle.y;
}

La première ligne teste la collision (CGRectIntersectsRect) entre la balle (balle.frame) et la première brique (brique1.frame), dans le cas où cette brique est toujours affichée (brique1.hidden == NO) :

if ((CGRectIntersectsRect(balle.frame,brique1.frame)) && (brique1.hidden == NO))

La troisième ligne cache la première brique :

brique1.hidden=YES;

Quant à la quatrième ligne, elle inverse le sens de progression vertical de la balle :

vitesseBalle.y = -vitesseBalle.y;

La brique 1 n'est pas la seule présente dans la vue. Vous devez donc écrire un code équivalent pour les briques 2 à 7 :

if ((CGRectIntersectsRect(balle.frame,brique2.frame)) && (brique2.hidden == NO))
{
brique2.hidden=YES;
vitesseBalle.y = -vitesseBalle.y;
}
if ((CGRectIntersectsRect(balle.frame,brique3.frame)) && (brique3.hidden == NO))
{
brique3.hidden=YES;
vitesseBalle.y = -vitesseBalle.y;
}
if ((CGRectIntersectsRect(balle.frame,brique4.frame)) && (brique4.hidden == NO))
{
brique4.hidden=YES;
vitesseBalle.y = -vitesseBalle.y;
}
if ((CGRectIntersectsRect(balle.frame,brique5.frame)) && (brique5.hidden == NO))
{
brique5.hidden=YES;
vitesseBalle.y = -vitesseBalle.y;
}
if ((CGRectIntersectsRect(balle.frame,brique6.frame)) && (brique6.hidden == NO))
{
brique6.hidden=YES;
vitesseBalle.y = -vitesseBalle.y;
}
if ((CGRectIntersectsRect(balle.frame,brique7.frame)) && (brique7.hidden == NO))
{
brique7.hidden=YES;
vitesseBalle.y = -vitesseBalle.y;
}

Exécutez l'application. Sous vos yeux ébahis, les briques disparaissent les unes après les autres !
Il nous reste encore à détecter la collision entre la balle et la raquette et à réagir en conséquence.

Ajoutez le test suivant dans la méthode boucleJeu :

If (CGRectIntersectsRect(balle.frame,raquette.frame))
{
if (balle.center.y < raquette.center.y)
vitesseBalle.y = -vitesseBalle.y;
}

La ligne 1 teste la collision entre la balle (balle.frame) et la raquette (raquette.frame) :

if(CGRectIntersectsRect(balle.frame,raquette.frame))

La ligne 3 teste si la balle se trouve plus bas que la raquette :

if (balle.center.y < raquette.center.y)

Dans ce cas, il convient d'inverser le sens de progression verticale de la balle pour qu'elle ne sorte pas de la vue :

vitesseBalle.y = -vitesseBalle.y;

Exécutez l'application. Ça y est, la balle rebondit sur la raquette. Bravo !
Il est temps de passer à l'étape suivante.

Musique de fond et bruits événementiels

Pour ajouter une musique de fond à l'application, vous utiliserez la technique étudiée dans la section « Jouer des éléments audio » du chapitre consacré au son. Reportez-vous à cette section pour avoir des renseignements détaillés sur sa mise en œuvre.

Une musique de fond, c'est bien, mais ce serait vraiment mieux si la balle produisait un bruit de balle lorsqu'elle frappe sur la raquette ou sur une brique. Pour cela, vous allez devoir utiliser un objet SystemSoundID.

Télécharger le son

Ajoutez un son au format CAF dans les ressources de l'application.
Cliquez sur le fichier ViewController.h dans le volet de navigation et ajoutez l'instruction suivante dans la définition de l'interface :

SystemSoundID bruit;

Rendez-vous dans le fichier ViewController.m et ajoutez cette instruction dans la méthode viewDidLoad :

AudioServicesCreateSystemSoundID(CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("pong"), CFSTR("caf"), NULL), &bruit);

Cette instruction met en relation le fichier audio à jouer (« pong.caf » dans cet exemple) et un objet SystemSoundID qui sera utilisé pour jouer le son (bruit dans cet exemple).

Maintenant, vous devez encore ajouter quelques instructions pour jouer le son « pong.caf » lorsque la balle entre en contact avec la raquette ou avec une brique.
Repérez le test de collision entre la balle et la raquette dans la méthode boucleJeu et complétez-le comme suit :

if(CGRectIntersectsRect(balle.frame,raquette.frame))
{
if(balle.center.y < raquette.center.y)
{
vitesseBalle.y = -vitesseBalle.y;
AudioServicesPlaySystemSound(bruit);
}
}

La ligne 6 joue le son « bruit » via la méthode AudioServicesPlaySystemSound.

Vous allez maintenant ajouter la même instruction dans les tests de collision entre la balle et chacune des briques. Voici par exemple à quoi doit ressembler le test de collision entre la balle et la brique 1 :

if ((CGRectIntersectsRect(balle.frame,brique1.frame)) && (brique1.hidden == NO))
{
brique1.hidden=YES;
vitesseBalle.y = -vitesseBalle.y;
AudioServicesPlaySystemSound(bruit);
}

Insérez cette même instruction dans les six autres tests de collision.

Perte de la balle

Je ne sais pas si vous avez remarqué, mais ce jeu présente un (petit) défaut : si le joueur n'arrive pas à rattraper la balle avec la raquette, celle-ci rebondit sur la partie inférieure de l'écran. Que diriez-vous d'ajouter un traitement relatif à la perte de la balle ? Par exemple… émettre un rire pour augmenter le stress du joueur.

Télécharger le son

Commencez par ajouter un son au format caf dans les ressources de l'application. Pour que ce son puisse être joué, vous devez définir un objet SystemSoundID et le relier à ce son. Ajoutez l'instruction suivante dans la partie interface du fichier ViewController.h :

SystemSoundID rire;

Vous allez maintenant agir sur le code. Cliquez sur ViewController.h dans le volet de navigation et ajoutez l'instruction suivante un peu avant la fin de la méthode viewDidLoad :

AudioServicesCreateSystemSoundID(CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("rire"), CFSTR("caf"), NULL), &rire);

Pour savoir si le joueur a laissé passer la balle, ajoutez le test suivant dans la méthode boucleJeu :

if (balle.center.y > self.view.bounds.size.height)
{
AudioServicesPlaySystemSound(rire);
balle.center = CGPointMake(100.0f, 100.0f);
}

Si l'ordonnée de la balle (balle.center.y) est supérieure à la hauteur de la vue (self.view.bounds.size.height), les instructions comprises entre les accolades sont exécutées.

L'instruction de la ligne 3 émet un son pour signifier la perte de la balle :

AudioServicesPlaySystemSound(rire);

Quant à l'instruction de la ligne 4, elle repositionne la balle pour poursuivre la partie :

balle.center = CGPointMake(100.0f, 100.0f);

La touche finale

Pour terminer cette application, nous allons afficher un message dans le Label lorsque toutes les briques ont été effacées et mettre fin à la boucle de jeu. Rendez-vous dans le fichier ViewController.m et ajoutez le bloc d'instructions suivant dans la méthode boucleJeu :

if ((brique1.hidden == YES) && (brique2.hidden == YES) && (brique3.hidden == YES) && (brique4.hidden == YES) && (brique5.hidden == YES) && (brique6.hidden == YES) && (brique7.hidden == YES))
{
stop3s.text = @"Bravo !";
[timer1 invalidate];
}

Ça y est, l'application est entièrement fonctionnelle. Amusez-vous bien !

Le code de l'application

Le code de l'application se trouve dans le dossier pong.

ViewController.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
@interface ViewController : UIViewController <AVAudioPlayerDelegate>
{
CGPoint vitesseBalle;
NSTimer *timer1;
AVAudioPlayer * audioPlayer;
SystemSoundID bruit;
SystemSoundID rire;
}
@property (weak, nonatomic) IBOutlet UIImageView *brique1;
@property (weak, nonatomic) IBOutlet UIImageView *brique2;
@property (weak, nonatomic) IBOutlet UIImageView *brique3;
@property (weak, nonatomic) IBOutlet UIImageView *brique4;
@property (weak, nonatomic) IBOutlet UIImageView *brique5;
@property (weak, nonatomic) IBOutlet UIImageView *brique6;
@property (weak, nonatomic) IBOutlet UIImageView *brique7;
@property (weak, nonatomic) IBOutlet UILabel *stop3s;
@property (weak, nonatomic) IBOutlet UIImageView *balle;
@property (weak, nonatomic) IBOutlet UIImageView *raquette;
@end
ViewController.m
#import "ViewController.h"
@implementation ViewController
@synthesize brique1;
@synthesize brique2;
@synthesize brique3;
@synthesize brique4;
@synthesize brique5;
@synthesize brique6;
@synthesize brique7;
@synthesize stop3s;
@synthesize balle;
@synthesize raquette;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"californie.jpg"]];
vitesseBalle = CGPointMake(10,15);
timer1 = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(boucleJeu) userInfo:nil repeats:YES];
UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
AudioSessionSetProperty (kAudioSessionProperty_AudioCategory, sizeof (sessionCategory), &sessionCategory);
NSData *soundFileData;
soundFileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"morceau.mp3" ofType:NULL]]];
audioPlayer = [[AVAudioPlayer alloc] initWithData:soundFileData error:NULL];
audioPlayer.delegate = self;
[audioPlayer setVolume:1.0];
[audioPlayer play];
AudioServicesCreateSystemSoundID(CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("pong"), CFSTR("caf"), NULL), &bruit);
AudioServicesCreateSystemSoundID(CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("rire"), CFSTR("caf"), NULL), &rire);
}
-(void) boucleJeu
{
balle.center = CGPointMake(balle.center.x + vitesseBalle.x , balle.center.y + vitesseBalle.y);
if (balle.center.x > self.view.bounds.size.width || balle.center.x < 0)
vitesseBalle.x = -vitesseBalle.x;
if (balle.center.y > self.view.bounds.size.height || balle.center.y < 0)
vitesseBalle.y = -vitesseBalle.y;
if(CGRectIntersectsRect(balle.frame,raquette.frame))
{
if(balle.center.y < raquette.center.y)
{
vitesseBalle.y = -vitesseBalle.y;
AudioServicesPlaySystemSound(bruit);
}
}
if (balle.center.y > self.view.bounds.size.height)
{
AudioServicesPlaySystemSound(rire);
balle.center = CGPointMake(100.0f, 100.0f);
}
if ((CGRectIntersectsRect(balle.frame,brique1.frame)) && (brique1.hidden == NO))
{
brique1.hidden=YES;
vitesseBalle.y = -vitesseBalle.y;
AudioServicesPlaySystemSound(bruit);
}
if ((CGRectIntersectsRect(balle.frame,brique2.frame)) && (brique2.hidden == NO))
{
brique2.hidden=YES;
vitesseBalle.y = -vitesseBalle.y;
AudioServicesPlaySystemSound(bruit);
}
if ((CGRectIntersectsRect(balle.frame,brique3.frame)) && (brique3.hidden == NO))
{
brique3.hidden=YES;
vitesseBalle.y = -vitesseBalle.y;
AudioServicesPlaySystemSound(bruit);
}
if ((CGRectIntersectsRect(balle.frame,brique4.frame)) && (brique4.hidden == NO))
{
brique4.hidden=YES;
vitesseBalle.y = -vitesseBalle.y;
AudioServicesPlaySystemSound(bruit);
}
if ((CGRectIntersectsRect(balle.frame,brique5.frame)) && (brique5.hidden == NO))
{
brique5.hidden=YES;
vitesseBalle.y = -vitesseBalle.y;
AudioServicesPlaySystemSound(bruit);
}
if ((CGRectIntersectsRect(balle.frame,brique6.frame)) && (brique6.hidden == NO))
{
brique6.hidden=YES;
vitesseBalle.y = -vitesseBalle.y;
AudioServicesPlaySystemSound(bruit);
}
if ((CGRectIntersectsRect(balle.frame,brique7.frame)) && (brique7.hidden == NO))
{
brique7.hidden=YES;
vitesseBalle.y = -vitesseBalle.y;
AudioServicesPlaySystemSound(bruit);
}
if ((brique1.hidden == YES) && (brique2.hidden == YES) && (brique3.hidden == YES) && (brique4.hidden == YES) && (brique5.hidden == YES) && (brique6.hidden == YES) && (brique7.hidden == YES))
{
stop3s.text = @"Bravo !";
[timer1 invalidate];
}
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
raquette.center = CGPointMake(location.x,raquette.center.y);
}
- (void)viewDidUnload
{
[self setBrique1:nil];
[self setBrique2:nil];
[self setBrique3:nil];
[self setBrique4:nil];
[self setBrique5:nil];
[self setBrique6:nil];
[self setBrique7:nil];
[self setStop3s:nil];
[self setBalle:nil];
[self setRaquette:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
@end

En résumé

  • Pour déplacer un objet sur l'écran, vous devez mettre en place un timer et modifier les coordonnées de l'objet dans la méthode activée à intervalle régulier par le timer.

  • Pour manipuler les coordonnées d'un objet, le plus simple consiste à utiliser des objets CGPoint, qui permettent de stocker deux valeurs flottantes (ici, les coordonnées X et Y de l'objet).

  • Pour contrôler les mouvements de toucher, définissez un objet UITouch, et spécifiez quelles actions de toucher doivent être capturées. La méthode locationInView, appliquée à l'objet UITouch, donne les coordonnées X, Y du toucher.

  • Pour détecter la collision entre deux objets sur l'écran, il suffit de comparer les coordonnées X et Y de leurs centres respectifs.

Exemple de certificat de réussite
Exemple de certificat de réussite