Que votre application fonctionne à la perfection ou que vous ayez buté sur un ou plusieurs points de détail, je vais vous montrer ma façon de voir les choses.
Comme toujours en programmation, il n'y a pas une, mais plusieurs solutions. C'est pourquoi je parle de « ma façon de voir les choses ». Il se peut donc que vous ayez écrit un tout autre code pour parvenir au même résultat.
Comme je vous l'ai suggéré dans la section « Principe du TP », le projet a été scindé en plusieurs étapes consécutives. Nous allons maintenant examiner chacune de ces étapes.
Création du projet
Définissez un nouveau projet de type
Single View Application et donnez-lui le nom « ver ».
Munissez-vous des ressources suivantes :
- une image JPG ou PNG de 320x480 pixels pour l'arrière-plan ;
- une image PNG transparente de 60x60 pixels pour le sprite ;
- un morceau MP3 pour l'arrière-plan sonore ;
- un son CAF qui sera émis lorsque le joueur pointe un ver avec son doigt ;
- un autre son CAF qui sera émis lors de la disparition d'un ver ou lorsque le joueur pointe l'arrière-plan et non le ver.
Pour stocker ces fichiers dans l'application, vous allez créer le dossier
Resources. Cliquez du bouton droit sur le dossier
ver dans le volet de navigation et sélectionnez
New Group dans le menu. Donnez le nom « Resources » à ce dossier et déplacez les cinq fichiers de ressource depuis le Finder dans le dossier
Resources de l'application. La figure suivante représente le volet de navigation que vous devriez avoir.
Ici,
fondver.jpg est l'image d'arrière-plan du jeu,
ver.png le sprite,
morceau.mp3 la musique d'arrière-plan,
pong.caf le bruit émis lorsque le joueur appuie sur un sprite et
rire.caf le bruit qui est émis lorsqu'un sprite disparaît sans que le joueur ait cliqué dessus.
Comme vous pouvez le voir, le sprite est un fichier PNG. Ce format n'a pas été choisi au hasard. En effet, les images PNG peuvent contenir des pixels transparents, ainsi le sprite se superposera parfaitement sur l'image d'arrière-plan (figure suivante)
Définition de l'écran de jeu
L'écran de jeu est vraiment simple, il contiendra deux contrôles :
- un Image View, pour afficher le ver ;
- un Label pour afficher le score.
Cliquez sur
MainStoryboard.storyboard dans le volet de navigation et ajoutez un contrôle
UIImageView ainsi qu'un contrôle
Label au canevas. Définissez l'outlet
leVer pour l'
Image View et l'outlet
leMessage pour le
Label.
Le fichier d'en-têtes doit maintenant ressembler à ceci :
Code : Objective-C | #import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UIImageView *leVer;
@property (weak, nonatomic) IBOutlet UILabel *leMessage;
@end
|
Affichage d'une image en arrière-plan
Cliquez sur
ViewController.m dans le volet de navigation et insérez la ligne suivante dans la méthode
viewDidLoad ;
Code : Objective-C | self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"fondver.jpg"]];
|
Cette technique a été utilisée et expliquée à maintes reprises dans les chapitres précédents, nous n'y reviendrons pas.
Mise en place du timer
Commencez par définir la variable d'instance
timer1 de classe
NSTimer dans le fichier d'en-têtes :
Code : Objective-C | interface ViewController : UIViewController <AVAudioPlayerDelegate>
{
NSTimer *timer1;
}
|
Puis insérez la ligne suivante dans la méthode
ViewDidLoad :
Code : Objective-C | timer1 = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(boucleJeu) userInfo:nil repeats:YES];
|
scheduledTimerWithTimeInterval:1.0f met en place un timer exécuté toutes les secondes. La méthode appelée a pour nom
BoucleJeu (
selector:@selector(boucleJeu)). Elle se répète indéfiniment, jusqu'à ce que l'application soit arrêtée par le joueur (
repeats:YES).
Vous vous doutez certainement de ce que sera l'étape suivante : la définition de la méthode
boucleJeu.
J'ai distingué trois étapes de jeu :
- une étape initiale, pendant laquelle un message indique au joueur que la partie va commencer ;
- une deuxième étape pendant laquelle le sprite est affiché sur l'écran ;
- une troisième étape pendant laquelle le sprite est dissimulé.
Pour définir ces trois étapes, j'ai choisi d'utiliser une variable d'instance de classe
int que j'ai appelée
etat. Cette variable est définie dans le fichier d'en-têtes :
Code : Objective-C | @interface ViewController : UIViewController <AVAudioPlayerDelegate>
{
NSTimer *timer1;
int etat; // Etat du jeu
}
|
Voici la structure de la méthode
boucleJeu :
Code : Objective-C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | -(void) boucleJeu
{
switch(etat)
{
case 0:
// Décompte de départ
break;
case 1:
// Affichage du ver
break;
case 2:
// Disparition du ver
break;
}
}
|
Il ne reste plus qu'à insérer des instructions à la suite des trois
case pour donner vie à la boucle de jeu
Case 0
Au lancement de l'application, le jeu doit afficher un décompte. L'étape initiale correspond donc à
etat = 0. Définissez cette valeur dans la méthode
viewDidLoad :
Code : Objective-C | - (void)viewDidLoad
{
[super viewDidLoad];
etat = 0;
timer1 = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(boucleJeu) userInfo:nil repeats:YES];
}
|
Au début de la partie, un message du type « Attention … 3 … 2 … 1 … C'est à vous » doit s'afficher dans le
Label. Chacune des parties de ce message, c'est-à-dire « Attention », « 3 », « 2 », « 1 » et « C'est à vous » est affichée pendant une seconde. Pour savoir où l'on se trouve dans le décompte, vous allez définir la variable d'instance
compteur de classe
int dans le fichier d'en-têtes :
Code : Objective-C | @interface ViewController : UIViewController
{
NSTimer *timer1;
int etat; // État du jeu
int compteur; // Compteur de départ de jeu
}
|
Puis vous allez initialiser cette variable à
4 dans la méthode
viewDidLoad :
Code : Objective-C | - (void)viewDidLoad
{
[super viewDidLoad];
etat = 0;
compteur = 4; // Compteur au départ du jeu
timer1 = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(boucleJeu) userInfo:nil repeats:YES];
}
|
Maintenant, vous allez compléter la méthode
boucleJeu pour afficher les messages dans le
Label :
Code : Objective-C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 | -(void) boucleJeu
{
switch(etat)
{
case 2:
// Disparition du ver
break;
case 1:
// Affichage du ver
break;
case 0:
// Décompte de départ
if (compteur == 4)
{
[leMessage setText:@"Attention"];
compteur--;
}
else if ((compteur >=1) && (compteur <=3))
{
leMessage.text = [NSString stringWithFormat: @"%i ...",compteur];
compteur--;
}
else if (compteur == 0)
{
[leMessage setText:@"C'est à vous !"];
compteur = 4;
etat = 1; //Affichage d'un ver
}
break;
}
}
|
Examinons ces instructions.
Au lancement du jeu,
compteur vaut
4. Le test
if (compteur == 4) étant vérifié, les instructions exécutées sont donc les suivantes :
Code : Objective-C | if (compteur == 4)
{
[leMessage setText:@"Attention"];
compteur--;
}
|
L'instruction de la ligne 3 affiche le message « Attention » dans le
Label et l'instruction de la ligne 4 décrémente la variable
compteur.
La méthode
boucleJeu se termine. Elle sera à nouveau exécutée dans une seconde puisque le timer mis en place a une période de 1 seconde.
À la deuxième exécution de la méthode
boucleJeu, compteur vaut
3. C'est donc cette portion du code qui est exécutée :
Code : Objective-C | else if ((compteur >=1) && (compteur <=3))
{
leMessage.text = [NSString stringWithFormat: @"%i ...",compteur];
compteur--;
}
|
L'instruction de la ligne 3 affiche la valeur du compteur dans le
Label :
3. La propriété
text du
Label étant de type
NSString, il est nécessaire d'effectuer une conversion
int -> NSString. C'est la raison d'être du message de la ligne 3.
La ligne 4 décrémente la variable
compteur qui vaudra
2 lors du prochain passage dans la méthode
boucleJeu.
Vous l'aurez compris, la même portion de code est exécutée lorsque compteur vaut
2, puis vaut
1. Une fois les messages « 2 » puis « 1 » affichés dans le
Label,
compteur vaut
0. C'est donc la dernière partie du code qui est exécutée :
Code : Objective-C | else if (compteur == 0)
{
[leMessage setText:@"C'est à vous !"];
compteur = 4;
etat = 1; //Affichage d'un ver
}
|
Dans ce cas, la ligne 3 affiche « C'est à vous » dans le
Label, la ligne 4 initialise le compteur à
4 et la ligne 5 affecte la valeur
1 à la variable
etat, ce qui signifie que la portion de code qui suit le
case 1 sera exécutée lors du prochain passage dans la méthode
boucleJeu.
Case 1
Lorsque
etat vaut
1, l'application doit afficher un ver sur l'écran pendant une durée aléatoire comprise entre 1 et 3 secondes.
Pour accomplir cette étape, vous aurez besoin de nouvelles variables. Complétez le fichier d'en-têtes comme suit :
Code : Objective-C | @interface ViewController : UIViewController
{
NSTimer *timer1;
int etat; // État du jeu
int compteur; // Compteur de départ de jeu
float leTemps; // Durée de l'état actuel
int largeur; // Largeur de l'écran
int hauteur; // Hauteur de l'écran
float posX; // Position en X du ver
float posY; // Position en Y du ver
}
|
La variable
leTemps sera utilisée pour stocker la durée de l'affichage du sprite.
Les variables
largeur et
hauteur contiendront la largeur et la hauteur en pixels du device. Ces valeurs sont importantes, car tous les devices n'ont pas la même définition.
Enfin, les variables
posX et
posY seront utilisées pour mémoriser la position du sprite sur l'écran.
Complétez le code situé entre les instructions
case 1: et
break; comme suit :
Code : Objective-C | case 1:
// Affichage du ver
posX = (arc4random() % (largeur - 60)) + 30;
posY = (arc4random() % (hauteur - 60)) + 30;
leVer.center = CGPointMake(posX, posY);
leVer.alpha = 1.0f;
leTemps = (arc4random() % 3) + 1; //Nombre aléatoire entre 1 et 3
[timer1 invalidate];
timer1 = [NSTimer scheduledTimerWithTimeInterval:leTemps target:self selector:@selector(boucleJeu) userInfo:nil repeats:YES];
etat = 2;
break;
|
La ligne 3 calcule la position en X du sprite. Pour cela, nous utilisons la fonction Objective-C
arc4random, qui renvoie un nombre entier compris entre 0 et 4 294 967 295. La valeur renvoyée étant bien supérieure à la taille des écrans des iPhones (tant horizontalement que verticalement), il est nécessaire de la réduire.
La variable
largeur représente la largeur en pixels de l'écran. Étant donné que le sprite est un carré de 60x60 pixels et que la fonction qui l'affiche sur l'écran se base sur son centre, il est nécessaire de restreindre les nombres tirés aléatoirement entre
30 et
largeur - 30.
La première partie du calcul (
arc4random() % (largeur - 60)) renvoie un nombre compris entre
0 et
largeur - 60. En lui ajoutant la valeur
30, on obtient la plage souhaitée :
30 à
largeur - 30.
La ligne 4 utilise un calcul similaire pour obtenir un nombre aléatoire compris entre
30 et
hauteur - 30 :
Code : Objective-C | posY = (arc4random() % (hauteur - 60)) + 30;
|
La ligne 5 affiche le ver sur l'écran aux coordonnées
posX,
posY calculées précédemment :
Code : Objective-C | leVer.center = CGPointMake(posX, posY);
|
La ligne 6 affecte la valeur
1.0f à la propriété
alpha du sprite pour le faire apparaître sur l'écran :
Code : Objective-C
La ligne 7 mémorise dans la variable
leTemps un nombre entier aléatoire compris entre
1 et
3. Ce nombre va correspondre au temps d'affichage du sprite. Libre à vous de le modifier comme bon vous semble.
Code : Objective-C | leTemps = (arc4random() % 3) + 1;
|
La ligne 8 désactive le timer actuel :
Code : Objective-C
Quant à la ligne 9, elle définit le nouveau timer basé sur la durée aléatoire calculée ligne 7 :
Code : Objective-C | timer1 = [NSTimer scheduledTimerWithTimeInterval:leTemps target:self selector:@selector(boucleJeu) userInfo:nil repeats:YES];
|
Enfin, la ligne 10 indique que le jeu a changé d'état. Lors de la prochaine exécution de la méthode
boucleJeu, ce sont les instructions qui suivent le
case 2: qui seront exécutées :
Code : Objective-C
Ah oui, j'allais oublier. Les variables
largeur et
hauteur n'ont pas été initialisées. Ajoutez les deux lignes suivantes dans la méthode
viewDidLoad pour réparer cette lacune :
Code : Objective-C | largeur = self.view.bounds.size.width; // Largeur de l'écran
hauteur = self.view.bounds.size.height; // Hauteur de l'écran
|
Case 2
Lorsque
etat vaut
2, l'application doit faire disparaître le ver qui est affiché. La durée de la disparition (c'est-à-dire le temps pendant lequel aucun ver n'est affiché sur l'écran) est très brève : 1/2 seconde. L'application doit également tester si le joueur a touché le ver avant qu'il ne disparaisse et, dans le cas contraire, émettre un son.
Pour accomplir cette étape, vous aurez besoin d'une nouvelle variable pour savoir si l'écran a été touché par le joueur. J'ai choisi d'appeler cette variable
aTouche. Définissez-la dans le fichier d'en-têtes. Tant que vous y êtes, définissez les variables
reussi et
rate pour tenir le compte des vers capturés et des vers ratés :
Code : Objective-C | int aTouche; // 1 si le joueur a touché l'écran, 0 sinon
int reussi; // Nombre de vers capturés
int rate; // Nombre de vers ratés
|
Ces trois variables étant définies, retournez dans le code et complétez les instructions entre
case 2: et
break; comme suit :
Code : Objective-C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | case 2:
// Disparition du ver
if (aTouche == 0)
{
rate++; // Sinon, le joueur n'a pas eu le temps de toucher l'écran, donc le ver est raté
leMessage.text = [NSString stringWithFormat: @"Vers attrapés %i ratés %i",reussi, rate];
AudioServicesPlaySystemSound(rire);
}
leVer.alpha = 0.0f;
leTemps = 0.5f;
[timer1 invalidate];
timer1 = [NSTimer scheduledTimerWithTimeInterval:leTemps target:self selector:@selector(boucleJeu) userInfo:nil repeats:YES];
etat = 1;
break;
|
Examinons ces instructions.
Par convention,
aTouche vaut
0 si l'écran n'a pas été touché par le joueur. Il vaut
1 dans le cas contraire.
La ligne 3 teste si l'écran n'a pas été touché. Dans ce cas, cela signifie que le joueur n'a pas eu le temps de capturer le ver.
Le nombre de vers ratés est donc incrémenté de 1 :
Code : Objective-C
Puis le
Label est mis à jour en conséquence :
Code : Objective-C | leMessage.text = [NSString stringWithFormat: @"Vers attrapés %i ratés %i",reussi, rate];
|
Et enfin, un son est émis :
Code : Objective-C | AudioServicesPlaySystemSound(rire);
|
La ligne 10 fait disparaître le ver de l'écran :
Code : Objective-C
La ligne 11 fixe le temps de la disparition à 1/2 seconde :
Code : Objective-C
Rappelez-vous, le ver doit disparaître pendant 1/2 seconde. C'est la raison pour laquelle la ligne 12 désactive le timer actuel et la ligne 13 le remplace par un nouveau, basé sur une période de 1/2 seconde :
Code : Objective-C | [timer1 invalidate];
timer1 = [NSTimer scheduledTimerWithTimeInterval:leTemps target:self selector:@selector(boucleJeu) userInfo:nil repeats:YES];
|
Enfin, la ligne 14 fait passer le jeu dans l'étape 1. La prochaine exécution de la méthode
boucleJeu provoquera donc l'affichage d'un nouveau sprite :
Code : Objective-C
J'espère que vous n'avez pas trop souffert en décortiquant la méthode
boucleJeu. Il faut bien avouer qu'elle était un peu longue. Mais vous serez certainement d'accord avec moi, ces instructions n'avaient rien d'insurmontable.
Pour souffler un peu, n'hésitez pas à lancer l'application. Vous verrez, elle fonctionne à la perfection en ce qui concerne la séquence de départ ainsi que l'affichage et la disparition des sprites.
J'ai une bonne nouvelle pour vous : cette méthode était de loin la plus complexe de l'application.
Tests de collisions
Vous allez maintenant écrire un peu de code pour tester si la position pointée par le joueur correspond à celle du sprite.
Pour cela, il vous suffit d'utiliser la méthode
touchesBegan pour obtenir les coordonnées du toucher. Comparez ces coordonnées avec celles du sprite et vous saurez si le joueur a bien ou mal visé.
Voici le code à mettre en place :
Code : Objective-C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
aTouche = 1; // Le joueur a touché l'écran
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
if ((abs(location.x - posX)<30) && (abs(location.y - posY)<30))
{
reussi++;
AudioServicesPlaySystemSound(bruit);
}
else
{
AudioServicesPlaySystemSound(rire);
rate++;
}
leMessage.text = [NSString stringWithFormat: @"Vers attrapés %i ratés %i",reussi, rate];
// Affichage d'un autre ver
[timer1 invalidate];
timer1 = [NSTimer scheduledTimerWithTimeInterval:0.0f target:self selector:@selector(boucleJeu) userInfo:nil repeats:YES];
etat = 2;
}
|
À la ligne 3, la variable
aTouche est initialisée à
1 pour indiquer que le joueur a touché l'écran.
Les lignes 4 et 5 récupèrent les coordonnées du toucher. La technique utilisée ici a été décrite dans la section « Immersion dans le code » du jeu de casse-briques. Reportez-vous-y si nécessaire.
La ligne 6 teste si le joueur a touché un sprite. Les entités
location.x et
location.y représentent les coordonnées du toucher. Quant à
posX et
posY, elles représentent le centre du sprite.
Si :
- la différence entre l'abscisse du toucher et l'abscisse du centre du sprite est inférieure à 30 ((abs(location.x - posX)<30)) ;
- la différence entre l'ordonnée du toucher et l'ordonnée du centre du sprite est inférieure à 30 ((abs(location.y - post)<30)) ;
cela signifie que le joueur a touché le sprite. Dans ce cas, le nombre de vers capturés est incrémenté de
1 (ligne 8) et un bruit de capture est émis (ligne 9).
Si le joueur a touché l'écran en dehors du sprite, un rire est émis (ligne 13) et le nombre de vers ratés est incrémenté de
1 (ligne 14).
Pour terminer, le timer actuel est désactivé (ligne 19), un nouveau timer à effet immédiat (
scheduledTimerWithTimeInterval initialisé à
0.0f) est défini (ligne 20) et l'application bascule dans l'étape 2 pour dissimuler le ver affiché.
Maintenant, il ne reste plus qu'à définir la « couche sonore » de l'application, c'est-à-dire la musique d'arrière-plan et les deux bruitages.
Musique d'arrière-plan
Nous avons déjà vu cette technique dans un chapitre précédent. Elle consiste à mettre en place un objet
AVAudioPlayer.
Commencez par cliquer sur la première entrée dans le volet de navigation, basculez sur l'onglet
Build Phases, développez l'élément
Link Binary with Libraries et ajoutez les frameworks
AVFoundation.framework et
AudioToolbox.framework.
Cliquez sur
ViewController.h dans le volet de navigation et faites référence aux deux frameworks avec des instructions
\#import :
Code : Objective-C | #import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
|
Toujours dans le fichier d'en-têtes, implémentez le protocole
AVAudioPlayerDelegate :
Code : Objective-C | @interface ViewController : UIViewController <AVAudioPlayerDelegate>
|
Enfin, définissez les objets suivants :
- audioPlayer de classe AVAudioPlayer ;
- bruit de classe SystemSoundID ;
- rire de classe SystemSoundID.
Code : Objective-C | @interface ViewController : UIViewController <AVAudioPlayerDelegate>
{
...
AVAudioPlayer *audioPlayer;
SystemSoundID bruit;
SystemSoundID rire;
}
|
Pour activer la musique de fond et rendre accessibles les deux effets spéciaux, ajoutez les instructions suivantes dans la méthode
viewDidLoad :
Code : Objective-C 1
2
3
4
5
6
7
8
9
10
11
12 | AudioSessionInitialize (NULL, NULL, NULL, (__bridge void *)self);
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);
|
Les lignes 1 à 9 mettent en place la musique de fond, comme nous l'avons vu dans le chapitre consacré au son.
Les lignes 11 et 12 mettent en place les sons
bruit et
rire.
Et voilà, l'application est entièrement opérationnelle. J'espère que vous avez pris autant de plaisir que moi à la développer !
Si vous testez cette application dans le simulateur iOS 5.0, il se peut que vous obteniez une erreur à rallonge dans la console.
Ne vous en faites pas : cette erreur n'en est pas vraiment une et l'application fonctionne à la perfection sur un iPhone, un iPod Touch ou un iPad tournant sous iOS 5. Un correctif devrait être intégré dans les prochaines mises à jour de Xcode.
Si cette erreur vous dérange vraiment, vous pouvez opter pour
une solution alternative.
L'application se trouve dans le dossier
ver. Voici le code de ses deux principaux fichiers.
Télécharger le projet
ViewController.h
Secret (cliquez pour afficher)
Code : Objective-C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 | #import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
@interface ViewController : UIViewController <AVAudioPlayerDelegate>
{
NSTimer *timer1;
int etat; // État du jeu
int compteur; // Compteur de départ de jeu
float leTemps; // Durée de l'état actuel
int largeur; // Largeur de l'écran
int hauteur; // Hauteur de l'écran
float posX; // Position en X du ver
float posY; // Position en Y du ver
int aTouche; // 1 si le joueur a touché l'écran, 0 sinon
int reussi; // Nombre de vers capturés
int rate; // Nombre de vers râtés
AVAudioPlayer *audioPlayer;
SystemSoundID bruit;
SystemSoundID rire;
}
@property (weak, nonatomic) IBOutlet UIImageView *leVer;
@property (weak, nonatomic) IBOutlet UILabel *leMessage;
@end
|
ViewController.m
Secret (cliquez pour afficher)
Code : Objective-C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158 | #import "ViewController.h"
#include <stdlib.h>
@implementation ViewController
@synthesize leVer;
@synthesize leMessage;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
-(void) boucleJeu
{
switch(etat)
{
case 0:
// Décompte de départ
if (compteur == 4)
{
[leMessage setText:@"Attention"];
compteur--;
}
else if ((compteur >=1) && (compteur <=3))
{
leMessage.text = [NSString stringWithFormat: @"%i ...",compteur];
compteur--;
}
else if (compteur == 0)
{
[leMessage setText:@"C'est à vous !"];
compteur = 4;
etat = 1; //Affichage d'un ver
}
break;
case 1:
// Affichage du ver
posX = (arc4random() % (largeur - 60)) + 30;
posY = (arc4random() % (hauteur - 60)) + 30;
leVer.center = CGPointMake(posX, posY);
leVer.alpha = 1.0f;
leTemps = (arc4random() % 3) + 1; //Nombre aléatoire entre 1 et 3
[timer1 invalidate];
timer1 = [NSTimer scheduledTimerWithTimeInterval:leTemps target:self selector:@selector(boucleJeu) userInfo:nil repeats:YES];
etat = 2;
aTouche = 0;
break;
case 2:
// Disparition du ver
if (aTouche == 0)
{
rate++; // Sinon, le joueur n'a pas eu le temps de toucher l'écran, donc le ver est raté
leMessage.text = [NSString stringWithFormat: @"Vers attrapés %i ratés %i",reussi, rate];
AudioServicesPlaySystemSound(rire);
}
leVer.alpha = 0.0f;
leTemps = 0.5f;
[timer1 invalidate];
timer1 = [NSTimer scheduledTimerWithTimeInterval:leTemps target:self selector:@selector(boucleJeu) userInfo:nil repeats:YES];
etat = 1;
break;
}
}
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
aTouche = 1; // Le joueur a touché l'écran
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
if ((abs(location.x - posX)<30) && (abs(location.y - posY)<30))
{
reussi++;
AudioServicesPlaySystemSound(bruit);
}
else
{
AudioServicesPlaySystemSound(rire);
rate++;
}
leMessage.text = [NSString stringWithFormat: @"Vers attrapés %i ratés %i",reussi, rate];
// Affichage d'un autre ver
[timer1 invalidate];
timer1 = [NSTimer scheduledTimerWithTimeInterval:0.0f target:self selector:@selector(boucleJeu) userInfo:nil repeats:YES];
etat = 2;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Arrière-plan
self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"fondver.jpg"]];
// Audio
AudioSessionInitialize (NULL, NULL, NULL, (__bridge void *)self);
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);
// Timer
etat = 0; // État 0 au départ du jeu : message de départ
reussi = 0; // Aucun ver capturé au départ
rate = 0; // Aucun ver raté au départ
compteur = 4; // Compteur au départ du jeu
largeur = self.view.bounds.size.width; // Largeur de l'écran
hauteur = self.view.bounds.size.height; // Hauteur de l'écran
timer1 = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(boucleJeu) userInfo:nil repeats:YES];
}
- (void)viewDidUnload
{
[self setLeVer:nil];
[self setLeMessage:nil];
[self setLeVer: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
|