====== Objet animé complexe ======
Dans [[nsi:langages:processing:trajectoire|Suivi de trajectoire]], c'est un point qui se déplace.
Supposons que l'on veuille déplacer un objet plus compliqué à dessiner qu'un point. Pour l'exemple, prenons ce poisson :
{{ :nsi:langages:processing:poisson.png?direct&200 |}}
===== Définir un objet =====
Pour cela on définit une classe ''Poisson'' qui permettra de prendre en charge tout le tracé d'un poisson.
class Poisson {
float size;
Poisson(float s) { // constructeur
/* size permettra de régler la taille du Poisson.
1 pour une taille de base, 2 pour une taille double...
*/
size = s; // contrairement à Python, pas besoin de préciser self.
// c'est une syntaxe Java
}
void display(float x, float y, float angle){
/* pour le tracer du poisson on précise a position x, y et son orientation */
pushMatrix();
translate(x, y);
rotate(angle);
scale(size);
line(0,0, -10,-5);
line(-10,-5,-10,5);
line(-10,5,0,0);
bezier(0,0,10,10,20,10,20,0);
bezier(0,0,10,-10,20,-10,20,0);
popMatrix();
}
}
==== utilisation de pushMmatrix() ====
Pour le tracer, deux fonctions sont très importantes : ''pushMatrix()'' et ''popMatrix()''.
Le principe est le suivant :
* on est capable de dessiner le poisson dans sa forme de base. Mais si on veut le tracer ailleurs, orienté autrement, en plus gros, il faudrait faire des calculs de translation, de rotation, de zoom.
* au lieu de faire ces calculs, on indique à processing les opérations que doit subir notre poisson de base. On change le contexte. On indique que l'on sera translater de ''x, y'', tourné de ''angle'' et zoomé de ''size''.
* Le dessin se fait dans ce contexte : 3 lignes pour la queue en forme de triangle, une courbe de Bézier pour l'arrondi de la tête.
* Le contexte est initialisé avec ''pushMatrix()'' et supprimé avec ''popMatrix()''.
Par ''matrix'' il faut comprendre que les opérations effectuées sont calculées avec des matrices de transformation. Les matrices sont un moyen commode de calculer les transformations de ce type.
===== Le programme entier =====
float t = 0;
Poisson p;
void setup() {
size(640, 400);
stroke(0,0,0);
p = new Poisson(1.0);
}
void draw(){
background(250,200,200);
t += 0.02;
float x = 320 + 120*cos(t);
float y = 200 + 80*sin(t - PI/3);
float angle = atan2(80*cos(t-PI/3), -120*sin(t));
p.display(x, y, angle);
}
class Poisson {
float size;
Poisson(float s) {
size = s;
}
void display(float x, float y, float angle){
pushMatrix();
translate(x, y);
rotate(angle);
scale(size);
line(0,0, -10,-5);
line(-10,-5,-10,5);
line(-10,5,0,0);
bezier(0,0,10,10,20,10,20,0);
bezier(0,0,10,-10,20,-10,20,0);
popMatrix();
}
}
Dans la fonction ''draw'' on calcule les positions ''x'' et ''y'' et l'orientation ''angle''. On fournit ces données à l'objet ''p'' pour qu'il mette à jour son affichage.
=== new ===
Vous pouvez noter que ''p'' est définit comme un objet de type ''Poisson'' mais n'est pas initialisé au début. On choisit de l'initialiser dans ''setup'' et pour cela on doit préciser ''new'' pour annoncer que l'on demande à réserver l'espace mémoire de ce nouvel objet.
On aurait tout aussi bien pu initialiser ''p'' dès le début.
=== atan2 ===
L'orientation du poisson se fait suivant la tangente de la trajectoire. On doit donc calculer
$$\begin{cases}x(t) = 320 + 120 \cos(t)\\y(t) = 200 + 80 \sin\left(t + \frac{\pi}{3}\right)\end{cases} \Rightarrow \begin{cases}x'(t) = -120 \sin(t)\\y'(t) = 80 \cos\left(t + \frac{\pi}{3}\right)\end{cases}$$
L'angle sera celui du vecteur de coordonnées $(x'(t);y'(t))$. C'est un calcul d'arctangente : $\arctan\left(\frac{y'(t)}{x'(t)}\right)$. Malheureusement ce calcul pose problème si $x'(t) = 0$. C'est pour cette raison que Processing fournit la fonction ''atan2''.