Previous Contents Next

Animation

The animation of graphics on a screen reuses techniques of animated drawings. The major part of a drawing does not change, only the animated part must modify the color of its constituent pixels. One of the immediate problems we meet is the speed of animation. It can vary depending on the computational complexity and on the execution speed of the processor. Therefore, to be portable, an application containing animated graphics must take into account the speed of the processor. To get smooth rendering, it is advisable to display the animated object at the new position, followed by the erasure of the old one and taking special care with the intersection of the old and new regions.

Moving an object
We simplify the problem of moving an object by choosing objects of a simple shape, namely rectangles. The remaining difficulty is knowing how to redisplay the background of the screen once the object has been moved.

We try to make a rectangle move around in a closed space. The object moves at a certain speed in directions X and Y. When it encounters a border of the graphical window, it bounces back depending on the angle of impact. We assume a situation without overlapping of the new and old positions of the object. The function calc_pv computes the new position and the new velocity from an old position (x,y), the size of the object (sx,sy) and from the old speed (dx,dy), taking into account the borders of the window.

# 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>
The function move_rect moves the rectangle given by pos and size n times, the trajectory being indicated by its speed and by taking into account the borders of the space. The trace of movement which one can see in figure 5.7 is obtained by inversion of the corresponding bitmap of the displaced rectangle.

# let move_rect pos size speed n =
let (x, y) = pos and (sx,sy) = size in
let mem = ref (Graphics.get_image x y sx sy) in
let rec move_aux x y speed n =
if n = 0 then Graphics.moveto x y
else
let ((nx,ny),n_speed) = calc_pv (x,y) (sx,sy) speed
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;
move_aux nx ny n_speed (n-1)
in move_aux x y speed n;;
val move_rect : int * int -> int * int -> int * int -> int -> unit = <fun>


The following code corresponds to the drawings in figure 5.7. The first is obtained on a uniformly red background, the second by moving the rectangle across the image of Jussieu.


# let anim_rect () =
Graphics.moveto 105 120;
Graphics.set_color Graphics.white;
Graphics.draw_string "Start";
move_rect (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 "End";;
val anim_rect : unit -> unit = <fun>
# anim_rect();;
- : unit = ()




Figure 5.7: Moving an object.


The problem was simplified, because there was no intersection between two successive positions of the moved object. If this is not the case, it is necessary to write a function that computes this intersection, which can be more or less complicated depending on the form of the object. In the case of a square, the intersection of two squares yields a rectangle. This intersection has to be removed.


Previous Contents Next