Animation
L'animation d'un graphisme à l'écran reprend des techniques de dessins
animés. La majeure partie du dessin ne change pas, seule la partie
animée doit modifier la couleur des pixels qui la compose. Un des
problèmes immédiatement rencontré provient de la vitesse
d'animation. Celle-ci peut varier selon la complexité du calcul et la
vitesse d'exécution du processeur. Ainsi une application graphique
animée pour être portable et donner le même effet doit tenir compte de
la rapidité du processeur. Pour avoir un rendu fluide il est
préférable d'afficher la nouvelle position de l'objet animé, puis
d'effacer l'ancienne, en tenant compte de leur intersection.
Déplacement d'un objet
Nous simplifions le problème du déplacement d'un objet en choisissant
des objets de forme simple que sont les rectangles. La difficulté restante
est de savoir réafficher le fond d'écran une fois l'objet déplacé.
On cherche à faire
évoluer un rectangle dans un espace clos. L'objet se
déplace selon une vitesse en X et Y, quand il rencontre un bord de la
fenêtre graphique, il rebondit selon son angle d'incidence. On se
place dans une situation sans recouvrement entre la nouvelle et
l'ancienne position de l'objet. La fonction calc_pv calcule,
à partir d'une position (x,y), de la taille de l'objet
(sx,sy) et d'une vitesse (dx,dy), la
nouvelle position et la nouvelle vitesse. Cette dernière tient
compte des bords de la fenêtre.
# let calc_pv (x,y) (sx,sy) (dx,dy) =
let nx1 = x+dx and ny1 = y + dy
and nx2 = x+sx+dx and ny2 = y+sy+dy
and ndx = ref dx and ndy = ref dy
in
( if (nx1 < 0) || (nx2 >= Graphics.size_x()) then ndx := -dx ) ;
( if (ny1 < 0) || (ny2 >= Graphics.size_y()) then ndy := -dy ) ;
((x+ !ndx, y+ !ndy), (!ndx, !ndy)) ;;
val calc_pv :
int * int -> int * int -> int * int -> (int * int) * (int * int) = <fun>
La fonction roule_fond déplace n fois le rectangle
donné par pos et taille selon la trajectoire
indiquée par sa vitesse vit en tenant compte des bords comme
décrit par la fonction ci-dessus. La trace du déplacement que l'on
obtient sur la figure 5.7 est obtenue par inversion du
bitmap correspondant au rectangle déplacé.
# let roule_fond pos taille vit n =
let (x, y) = pos and (sx,sy) = taille in
let mem = ref (Graphics.get_image x y sx sy) in
let rec roule_aux x y vit n =
if n = 0 then Graphics.moveto x y
else
let ((nx,ny),n_vit) = calc_pv (x,y) (sx,sy) vit
and old_mem = !mem in
mem := Graphics.get_image nx ny sx sy ;
Graphics.set_color Graphics.blue;
Graphics.fill_rect nx ny sx sy;
Graphics.draw_image (inv_image old_mem) x y;
roule_aux nx ny n_vit (n-1)
in roule_aux x y vit n ;;
val roule_fond : int * int -> int * int -> int * int -> int -> unit = <fun>
Le code suivant correspond aux dessins de la figure 5.7. Le
premier est obtenu sur fond uniformément rouge, le second, en
déplaçant le rectangle sur l'image de Jussieu.
# let anim_rect () =
Graphics.moveto 105 120 ;
Graphics.set_color Graphics.white;
Graphics.draw_string "Début" ;
roule_fond (140,120) (8,8) (8,4) 150 ;
let (x,y) = Graphics.current_point() in
Graphics.moveto (x+13) y ;
Graphics.set_color Graphics.white;
Graphics.draw_string "Fin" ;;
val anim_rect : unit -> unit = <fun>
# anim_rect();;
- : unit = ()
Figure 5.7 : Code du déplacement d'un objet
Le problème a été simplifié dans la mesure où il n'y a pas
d'intersection entre deux positions successives de l'objet
déplacé. Si tel n'est pas le cas, il faut écrire une fonction de
calcul de cette intersection qui est plus ou moins compliquée selon la
forme de l'objet. Dans le cas présent d'un carré, l'intersection de
deux carrés donne un rectangle. C'est celui-ci qu'il faut alors
effacer.