Licence Profesionnelle TAI
Td de Programmation Orientée Objet – JAVA

Philippe Genoud
dernière modification par Philippe.Genoud@imag.fr.

Objectifs :Il s'agit de se familiariser avec les notions d'héritage, de réutilisation et d'abstraction et de polymorphisme et à leur réalisation dans le langage JAVA.


Exercice 1

Il s'agit d'écrire en JAVA une application de jeu. Ce jeu consiste à déplacer un curseur (à l'aide de la souris, par exemple) et à détruire des cibles qui apparaissent dans une fenêtre sur l'écran.

Le repère associé à une fenêtre a son origine dans le coin supérieur gauche, l'axe des y est orienté vers le bas (repère indirect). La figure qui suit montre par exemple une fenêtre de jeu de taille 800x600 pixels (points).

Dans cet exercice, on ne s'intéressera qu'à la programmation des cibles. On supposera donc que la fenêtre de jeu est représentée par un objet de classe FenêtreDeJeu qui propose deux méthodes :

Un cible est définie par une position (couple de coordonnées entières) et une forme, qui peut être soit un cercle soit un carré. Si la cible est circulaire sa position donne le centre du cercle la matérialisant, si la cible est carrée sa position indique les coordonnées de son coin supérieur gauche.

L'utilisateur peut déplacer le curseur de tir. Lorsque le curseur se trouve à l'intérieur d'une cible (carré ou cercle) et que l'utilisateur enclenche le tir la cible est atteinte. Le comportement d'une cible lorsqu'elle est atteinte varie selon la nature de la cible.

Pour représenter les différents types de cibles les classes suivantes sont définies :

La classe Cible

La classe Cible définit ce qui est commun à toutes les cibles :

Les informations (attributs ou variables d'instance) associées à une cible sont :

La position initiale est fixée lors de la création d'une cible (les valeurs de  l'abscisse et de l'ordonnée de la position sont passées en paramètre du constructeur de la classe Cible ainsi que la référence de l'objet FenêtreDeJeu dans lequel le jeu se déroule).

Les opérations (méthodes) définies pour une cible sont :

La classe CibleCirculaire

La classe CibleCirculaire définit comme son nom l'indique des cibles de forme circulaire. Lorsqu'elles sont atteintes par un tir du joueur, les cibles circulaires ont le comportement suivant (comportement implémenté dans la méthode choc()) :
la cible voit son rayon diminuer d'une unité (un pixel). Lorsque ce rayon devient nul, la cible est repositionnée de façon aléatoire dans la fenêtre de jeu et le rayon reprend sa valeur initiale (valeur qu'avait le rayon de la cible avant d'être atteinte pour la première fois et fixée lors à la création de la cible).

La classe CibleCirculaireMobile

La classe CibleMobileCirculaire est une sous-classe de la classe CibleCirculaire. Cette classe va permettre la gestion d'un nouveau type de cibles : les cibles mobiles. Ces cibles ont un mouvement de translation horizontal et se déplacent d'un bord à l'autre de la fenêtre (lorsque la cible rencontre un des bords de la fenêtre, elle "rebondit" et son déplacement se fait alors dans le sens opposé).

La classe CibleCirculaireMobile enrichit la classe CibleCirculaire d'une nouvelle variable d'instance :

D'autre part, une nouvelle méthode est associée à ce type de cibles :

Enfin, les cibles circulaires mobiles ont un comportement particulier lorsqu'elles sont atteintes par le tir du joueur (méthode choc()). En effet, non seulement leur rayon diminue d'une unité (avec les mêmes conséquences que pour les cibles fixes de type Cible si le rayon devient nul), mais en plus, leur sens de déplacement s'inverse (comme lorsqu'elles rencontrent un des bords verticaux de la fenêtre).

Question 1) Donner une description synthétique des différentes classes nécessaires à la représentation des cibles. Cette description sera fournie sous forme de diagramme de classes en notation UML.

Question 2) Ecrire le code JAVA de la classe Cible. Définir ses variables d'instance (attributs), écrire son constructeur et ses différentes méthodes.

Question 3) Ecrire le code JAVA de la classe CibleCirculaire. Définir ses variables d'instance (attributs), écrire son constructeur et ses différentes méthodes.
(Lors d'un choc, pour calculer la nouvelle position de la cible on fera appel à la fonction random() de la classe Math (Math.random() retourne un double tiré au hasard dans l'intervalle [0..1]).

Question 4) Ecrire le code JAVA de la classe CibleCirculaireMobile. Définir ses variables d'instance (attributs), écrire son constructeur et ses différentes méthodes.

Question 5) Dans le fragment de code suivant, indiquer pour chaque instruction si celle-ci est valide ou non (c.a.d. si s'elle sera acceptée ou non par le compilateur JAVA)  en justifiant chacune de vos réponses.

On supposera que laFenetre est une variable qui contient une référence valide vers un objet de classe FenetreDeJeu.
Les paramètres 125,340,20 pour la CibleCirculaireMobile sont respectivement l'abscisse et l'ordonnée de sa position initiale et son rayon initial.
Les paramètres 100,100,10,-3 pour la CibleCirculaireMobile sont respectivement l'abscisse et l'ordonnée de sa position initiale, son rayon initial et la valeur de son déplacement élémentaire.

Question 6) Le programme principal de l'application est donné par l'algorithme suivant :

Creer la Fenetre de jeu
Créer un EC ensemble de cibles dans cette fenêtre
   (les cibles sont générées de manière alétoire)
tantque la partie n'est pas finie faire
     dessiner les cibles

     récuperer la position x,y du curseur du joueur
     pour chaque cible dans EC
         si la cible contient le curseur
              appliquer à la cible le "traitement de choc"
         si la cible est une cible mobile
              deplacer la cible
fintantque

Ecrire les instructions Java correspondant aux parties de l'algorithme ci-dessus écrites en gras, sachant que pour gérer l'ensemble de cibles on décide d'utiliser un objet de la classe ArrayList définie dans java.util. Cette classe, dont voici un extrait de la documentation, se comporte comme un tableau dynamique. Elle permet de permet de construire dynamiquement une liste d'objets, chaque objet présent dans la liste pouvant être accédé directement par un index (0 pour le premier élément de la liste, 1 pour le deuxième, etc....). Contrairement aux tableaux il n'est pas nécessaire de spécifier la taille d'un ArrayList, de plus celle-ci croit dynamiquement au fur et à mesure que la liste des éléments qu'il contient augmente.

Constructor Summary
ArrayList()
          Constructs an empty list.
...
ArrayList(int initialCapacity)
          Constructs an empty list with the specified initial capacity.

 

Method Summary
 void add(int index, Object element)
          Inserts the specified element at the specified position in this list.
 boolean add(Object o)
          Appends the specified element to the end of this list.
... ...
 Object get(int index)
          Returns the element at the specified position in this list.
... ...
 int size()
          Returns the number of elements in this list.
... ...
 

Exercice 2 , Expérimentation sur machine :

Dans le Td précédent, vous avez été ammenés à modifier la classe Dessin afin de pouvoir afficher non plus des VisagesRond, mais des Chenilles. Maintenant que vous connaissez le concept de classes abstraites et d'interfaces, comment procéderiez vous pour que l'application puisse animer simultanément des VisagesRond et des Chenilles ? Donner un diagramme de classe représentant les différentes classes de votre application et leurs relations.

Modifiez l'application d'animation afin d'afficher indifféremment dans la même fenêtre des chenilles et des visages créés de manière aléatoire. Créez ensuite une nouvelle classe d'objets animables en procédant de manière à ne pas avoir à modifier le code de la classe Dessin.