Architecture de notre système
particulaire
Grâce aux capacités des langages orientés objets,
nous avons pu concevoir une architecture où modularité,
évolutivité et réutilisabilité ne sont pas
des mots en l'air.
Agora'Sim est fondé sur un système particulaire.
C'est-à-dire que chaque mobile est représenté par une
particule dont on calcule la position à intervalles de temps
régulier. On peut distinguer 4 parties : le moteur, l'affichage,
les particules, et l'environnement.
Les particules : le polymorphisme
Toutes les particules de notre système sont des objets dont la classe (le type) dérive d'une classe "Mobile" dite abstraite. On ne peut pas instancier d'objet directement à partir d'une classe abstraite car on y déclare en général des méthodes (des fonctions) qui ne sont pas implémentées. Les classes abstraties sont donc destinées à être dérivées en d'autres classes qui devront imple´menter toutes les fonctions déclarées dans leur classe "mère" sous peine de devenir elle-même une classe abstraite.
Voyons l'utilité de ce mécanisme en prenant pour exemple
Agora'Sim.
Dans notre simulateur, tous les mobiles sont issus d'une classe abstraite
"Mobile". Cette classe possède deux fonctions qui ne sont pas
implémentées : bouge() et trace(). Nous sommes donc
obligés de créer de nouvelles classes qui dérivent
de Mobile pour implémenter les comportements de nos particules.
L'intérêt est que pour tout le programme, les particules sont
toutes vues comme étant des objets de types Mobile. Quelles que
soient les impléemntations qui sont faites pour les particules,
le moteur saura les faire bouger.
Ce mécanisme s'appelle le polymorphisme. Il nous permet de
développer des particules avec de nouveaux comportements en n'ayant
rien à modifier, et donc rien à revalider sur le reste du
logiciel.
Les particules : l'hérédité
On a vu que toutes nos particules sont issues de classes dérivant la classe Mobile. C'est en fait encore un peu plus subtil. Le but de la manoeuvre est d'éviter la redondance, de ne pas avoir à coder, tester, deboguer plusieurs fois ce qui peut l'être une fois pour toutes.
La classe Mobile a tout d'abord été dérivé en une classe MobPhys qui implémente tous les comportements physiques des particules. MobPhys s'occupe de calculerla position et la vitesse de la particule en fonction de l'accélération à laquelle elle est soumise. Les collisions avec les murs et les autres particules sont aussi gérées ici. Seule la méthode bouge() est redéfinie, MobPhys reste donc une classe abstraite.
La classe MobPhys est à son tour dérivée en une classe MobComp. Cette classe regroupe toutes les méthodes nécessaires à l'élaboration du comportement des particules. Calculer le vecteur d'accélération à fournir pour tourner à gauche par exemple.
Enfin, les classes finales utilisent les services définis dans MobComp pour "construire" le vecteur d'accélération dont elles ont besoin, et le donnent en pâture aux méthodes définies dans MobPhys pour concrétiser leur déplacement.
Ce mécanisme, l'hérédité, nous a ainsi permis de modéliser de nombreuses particules aux comportements différents pour animer toutes les applets de ce site, avec très peu de code spécifique à chacune.
On pourrait répondre qu'une bibliothèque de fonctions rend le même service. En fait l'hérédité permet bien plus. Il est par exemple possible à MobPhys de bloquer aux classes qui la dérivent l'accès aux variables de la classe Mobile. Ainsi, pour changer la position du mobile, on est obligé d'utiliser les fonctions offertes par MobPhys (c'est l'encapsulation). On met ainsi les variables de Mobile en sécurité contre les erreurs de manipulation. Le fait d'être obligé de passer par des méthodes (fonctions) pour accéder aux données permet également de changer l'organisation interne des classes sans en changer les méthodes, ce qui a l'avantage d'être totalement transparent pour les autres classes.
L'environnement : même combat
Les "plans" utilisés par Agora'Sim sont un ensemble de zones qui offrent des services tels que tester si un mobile est dedans. Comme pour les particules, le polymorphisme est utilisé pour que l'utilisation des zones soit indépendante de leur implémentation.
Concrètement, on se moque de savoir si les zones sont rondes ou rectangulaires. Comme elle dérivent toutes de la classe Zone, l'affichage sait les afficher et les mobiles savent tester s'ls sont ou non dedans.
L'affichage : une offre de service
La méthode d'affichage est assez intéressante. Le module d'affichage ne sait afficher ni les zones ni les mobiles, puisque cela dépend de leur implémentation. Par contre, il sait qu'il peut leur demander de se tracer eux-mêmes. Tous les mobiles et toutes les zones sont en effet obligées de savoir le faire car c'est spécifié dans les classes abstraites Mobile et Zone.
De leur côté, les mobiles et les zones sont bien embêtés car ils ne connaissent que leur propre système de coordonnées (en flottants) et n'ont aucune idée de la rèsolution de l'écran ou du facteur de zoom utilisé. On peut presque dire que leur principal souci est de ne pas avoir à se soucier de ce genre de chose...
La solution utilisée est la suivante :
Le procédé est rigoureusement identique pour les zones.
Le moteur : jeu, thread et match
Le moteur de la simulation est une simple boucle qui demande aux mobiles de bouger (il demande en fait à la liste de mobiles...) puis à l'affichage de se rafraîchir. Le moteur attend un petit moment avant de recommencer.
Notre moteur est un thread, c'est-à-dire une unité de calcul
parallèle. Il s'exécute en même temps que le reste du
programme.
Ainsi, même si l'affichage est très lent, le moteur continue
à calculer de nouvelles positions. Si quand il a terminé
une boucle, l'affichage n'a pas fini d'afficher les résultats de
la suivante, et bien tant pis ! Ainsi, un affichage lent donne une
animation saccadée, mais non ralentie.