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
1
0
5
1
2
0
;
Graphics.set_color
Graphics.white;
Graphics.draw_string
"Début"
;
roule_fond
(1
4
0
,
1
2
0
)
(8
,
8
)
(8
,
4
)
1
5
0
;
let
(x,
y)
=
Graphics.current_point()
in
Graphics.moveto
(x+
1
3
)
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.