Le but du jeu ? Détruire les seules briques situées
en haut.
Je ne saurais dire pourquoi mon casse-briques est si lent dans
sa version Shockwave. Sous forme d'animation Director, ça
tourne si vite que c'en est presque injouable ! A mon avis, c'est
java qui est lent en animation.
Un chose est sûre, c'est là un excellent prétexte
pour aborder le Lingo objet puisque deux balles y ont chacune un
comportement autonome et pourtant similaire. Ces deux balles doivent
savoir quoi faire d'elles-mêmes !
Plantons le décors pour commencer . A l'exception notable
des balles en mouvement pour lesquels un seul acteur bitmap 1 bit
colorisé a été utilisé deux fois , tout
l'écran est composé d'acteurs de type forme. Ces acteurs
sont lent en animation mais extrêmement légers et conviennent
parfaitement à une construction de ce type. Les briques ne
sont faites que d'un seul acteur forme rectangulaire placé
39 fois sur différentes pistes et colorisé.
Comme on le voit sur cette copie d'écran, c'est un acteur
forme (ici en bleu pale mais invisible en réalité)
qui est chargé de contenir les mouvement du palet (un autre
acteur forme). Il suffit de placer dans un script d'initialisation
l'instruction : set the constraint of sprite (numéro
de sprite du palet) to (numéro de sprite de l'acteur forme
invisible). Le palet dès lors ne sortira pas de la zone qu'on
veut lui voir couvrir. Afin qu'il suive les mouvements de la souris,
le script d'image est ainsi rédigé :
on exitFrame
set the loch of sprite (numéro de sprite du palet) to
the mouseh
go to the frame
end
Le décors étant planté il nous reste à
animer les balles et à gérer leurs collisions avec
les murs, le palet et les briques.
Ici parce que deux balles au comportement identique sont en jeu,
la programmation objet s'impose tout naturellement.
Pas question de gérer chaque balle isolément. Il
faut définir un objet balle de façon abstraite. affecter
à cet objet un comportement type et c'est seulement après
cela que nous créerons de vraies balles, autant que nous
voudrons, en leur attachant ce comportement.
Posons nous la question de savoir ce que nous voulons de chacune
de ces balles.
Nous voulons d'abord que chacune se déplace librement :
nous devons pour chacune être en mesure de modifier sa position.
Nous souhaitons que chacune change de sens lorsqu'elle vient heurter
un mur, le palet ou une brique : l'orientation de chacune de ses
balles doit donc nous être accessibles.
Nous allons définir UN MODÈLE TYPE BALLE possédant
les propriétés et susceptible des comportements génériques
que nous souhaitons pour toutes les vraies balles :
Les propriétés d'abord communes à chaque balle
:
Toute balle aura une position (horizontale et verticale) donc deux
propriétés POSH et POSV ; une orientation vers le
haut et la gauche, le bas et la gauche, le haut et la droite, etc.
donc un sens horizontal et vertical de déplacement : SENSH
et SENSV . Chaque balle enfin devra correspondre à un sprite
physiquement sur la scène sinon son existence restera très
virtuelle. Toutes les balles se verront donc attaché un numéro
de piste, soit une propriété NUMERODESPRITE .
Plaçons maintenant cette définition DE TOUTE BALLE
à venir dans un script Lingo. Par le menu Fenêtre,
commande Script nous accédons à un script d'animation
vierge. Nous nommons ce script PARENTDESBALLES et nous y déclarons
les propriétés communes à toutes les balles :
property POSH, POSV, SENSH, SENSV, NUMERODESPRITE
Chaque fois que nous devrons utiliser une nouvelle balle, nous
choisirons un sprite et nous devrons l'indiquer à Director.
Ce numéro ne sera pas toujours le même puisque nous
voulons utiliser plusieurs balles : nous désignons ce numéro
à venir par la variable UNSPRITE.
on new me, UNSPRITE
set NUMERODESPRITE to QUELSPRITE
set POSH to the locH of sprite NUMERODESPRITE
set POSV to the locV of sprite NUMERODESPRITE
set SENSH to 1
set SENSV to -1
return me
end
Qu'est-ce que cela veut dire ? Rien d'autre que ceci : toutes
les balles auront une propriété position qui, pour
commencer, sera la positon du sprite associé sur la scène.
Toutes les balles se reconnaîtront dans la variable "me".
Maintenant toutes les balles devront se mouvoir librement, nous
allons définir un comportement type pour toutes les balles
que nous pourrions être amené à utiliser :
Placé sur le même script un gestionnaire on stepFrame
va nous permettent d'instruire ce que toute balle devra faire à
chaque fois que la tête de lecture reviendra sur l'image.
Décidons que toutes les balles, sauf à sortir de la
zone de jeu, devront voir leur position modifiée de deux
pixels. Bien sûr le sprite associé sur la scène
devra se mouvoir aussi :
on stepFrame me
rebonditContreLesMursEtLePalet me
set POSH to POSH + 2 * SENSH
set POSV to POSV + 2 * SENSV
set the loc of sprite NUMERODESPRITE to point( POSH, POSV)
end
Dans la variable "me", toute les balles se reconnaîtront
et exécuteront les instructions.
Évidemment, l'instructions rebonditContreLesMursEtlePalet
n'a aucun sens pour Lingo. Il nous faut la définir. cette
instruction de comportement aura un argument : à chaque
fois une des balles créées : par convention "me".
on rebonditContreLesMursEtlePalet me
case true of
( POSH >= the right of sprite LA_SURFACE_DE_JEU ) :
set SENSH to SENSH * -1
set POSH to POSH + 4 * SENSH
( POSH <= the left of sprite LA_SURFACE_DE_JEU ) :
set SENSH to SENSH * -1
set POSH to POSH + 4 * SENSH
( POSV <= the top of sprite LA_SURFACE_DE_JEU ) :
set SENSV to SENSV * -1
set POSV to POSV + 4 * SENSV
( POSV >= the bottom of sprite LA_SURFACE_DE_JEU ) :
Ce comportement indique à toutes les balles de modifier
leurs propriétés SENSH et SENV à chaque fois
qu'une balle heurte un mur ou le palet. Nous avons également
pris la précaution de repousser vivement (4 pixels) les balles
en sens inverse, vers l'intérieur de la zone de jeu donc
pour éviter qu'une fois le mur franchi, l'instruction qui
inverse le sens ne soit exécutée infiniment.
À ce stade de notre travail, nous pouvons déjà
effectuer un test :
Créons deux balles réelles en attachant à
deux sprites (40 et 41) placés sur la scène le comportement
que nous avons défini.
Dans la fenêtre message nous saisissons :
set UNEBALLE to new(script "PARENTDESBALLES", 40)
set UNEAUTREBALLE to new(script "PARENTDESBALLES", 41)
Immédiatement les balles se meuvent dans l'espace de jeu
et rebondissent contre les murs. Bon début ! Essayez dans
Director, vous verrez comme ça va vite.
Il nous reste quelques améliorations : d'abord la gestion
des collisions avec les briques car pour l'instant nos balles se
moquent de ces obstacles; le lancement du jeu par l'utilisateur
(qui ne va pas utiliser la fenêtre message lui !) et enfin,
pour que le jeu prenne sens, la vérification du score en
fin de partie.
Pour gérer les collisions avec les briques, il nous faut
reprendre le script que nous avons nommé PARENTDESBALLES,
pour ajouter une instruction supplémentaire au gestionnaire
on stepFrame :
on stepFrame me
rebonditContreLesMursEtLePalet me
gereCollisionsAvecBriques me
set POSH to POSH + 2 * SENSH
set POSV to POSV + 2 * SENSV
set the loc of sprite NUMERODESPRITE to point(POSH, POSV)
end
L'instruction gereCollisionsAvecBriques est détaillée
ensuite comme suit (toujours dans la même fenêtre de
script) :
on gereCollisionsAvecBriques me
global CIBLES
-- On utilise une liste des 39 sprites briques,
-- liste créée dans un script d'initialisation
repeat with n in CIBLES
-- Pour chacune des 39 briques ("n") on vérifie :
if sprite NUMERODESPRITE intersects sprite n then
-- auquel cas on renvoie la balle
-- et on rend la brique invisible
set SENSV to SENSV* -1
set the visible of sprite n to false
set POSV to POSV + 4 * SENSV
-- Il convient d'ôter cette brique
-- invisible de la liste des cibles
-- et d'arrêter le test :
deleteOne CIBLES, n
exit repeat
end if
end repeat
-- maintenant on veille à ce que le
-- jeu prenne fin quand il n'y a plus
-- de cibles :
-- admettons que l'on ait placé les briques
-- à détruire sur les pistes 28 à 39; s'il
ne
-- reste plus qu'une de celles-là alors c'est
-- perdu puisqu'il n'y a plus de briques violettes.
if getAt(CIBLES, 1) >= 28 then arretePerdu
-- s'il ne reste plus que des briques violettes
-- (placées sur les pistes jusque 28), alors
-- c'est gagné
if getLast (CIBLES) < 28 then arreteGagne
end
Nous vous laissons le soin de rédiger ces deux gestionnaires
arretePerdu et arreteGagne. Apparition du score dans un champs,
marquage sonore... mais il nous semble important de mentionner la
NÉCESSITÉ d'y inclure les instructions détruisant
les objets créés (les balles) et libérant la
mémoire :
on arreteGagne
global UNEBALLE, UNEAUTREBALLE
set the text of member x to count(CIBLES)
set UNEBALLE to 0
set UNEAUTREBALLE to 0