:: Enseignements :: Licence :: L3 :: 2016-2017 :: Programmation Objet avec Java ::
[LOGO]

TP noté L3 Info - À vous de jouer!


Le but de ce TP est de créer des personnages de jeu vidéo qui peuvent se battre entre eux et qui peuvent améliorer leur équipement en fonction de ce qu'ils trouvent dans le monde du jeu.
Rappel: vous devez utiliser Eclipse, et configurer le workspace d'Eclipse (File > Switch WorkSpace) pour qu'il corresponde au répertoire EXAM que vous avez dans le home de votre session de TP noté. Attention, ce TP est corrigé pour partie de façon automatique! Il est donc très important que le nom des classes, des champs et des méthodes que l'on vous demande soit respectés.
Vous écrirez toutes les classes de ce TP noté dans un package nommé fr.umlv.game. Vous devez tester toutes les méthodes demandées et vous écrirez tous vos tests dans la classe Test de ce package.
On rappelle qu'il est également possible de compiler et exécuter dans un terminal de la façon suivante. En se plaçant dans le dossier qui contient les répertoires src et bin:
    javac src/fr/umlv/game/*.java -d bin/
    java -cp bin fr.umlv.game.Test

La javadoc est accessible en local: file:///usr/local/apps/java8/docs/api/index.html.
Les pdf du cours sont accessibles ici.

Exercice 1 - Les barbares ont deux mains

Les premiers personnages que nous allons créer sont des barbares qui peuvent se battre avec une arme dans chaque main. Nous allons donc commencer par fabriquer des armes.

  1. Les armes seront représentées par la classe Weapon. Chaque arme a un nom name et un nombre entier de points de dégâts damage.
    Écrire la classe Weapon, ainsi que son constructeur qui prend en paramètre le nom et les points de dégâts. Attention, une arme doit toujours avoir un nom.
    Faîtes en sorte que l'on puisse afficher une arme avec le code suivant:
        Weapon sword = new Weapon("Excalibur", 50);
        System.out.println(sword); // Excalibur (50)
       
    L'affichage doit indiquer le nom de l'arme et ses points de dégâts, en respectant le format de l'exemple ci-dessus. Écrire les test correspondants dans la classe Test.

  2. Ajouter une méthode permettant de connaître le nombre de point de dégâts causés par une arme.

  3. Un barbare est un personnage du jeu qui a un nom name, un nombre (entier) de points de santé health et 2 mains leftHand (gauche) et rightHand (droite) qui tiennent des armes.
    Écrire la classe Barbarian, ainsi que son constructeur qui prend en paramètre le nom, les points de santé et les armes à placer dans chaque main. Attention, un barbare ne resterait jamais les mains vides...
    Faîtes en sorte que l'on puisse afficher un barbare avec le code suivant:
        Barbarian hulk = new Barbarian("Hulk", 100, new Weapon("Dagger", 8), new Weapon("Axe", 12));
        System.out.println(hulk); // Barbarian Hulk *100*, L : Dagger (8), R : Axe (12)
       
    L'affichage doit indiquer le nom du barbare, ses points de santé et les armes qu'il tient dans ses mains, en respectant le format de l'exemple ci-dessus.

  4. Ajouter une méthode permettant d'obtenir le nom du barbare.
    Ajouter également une méthode attack qui renvoie ses points d'attaque, c'est à dire la somme des point de dégâts des armes tenues dans les mains du barbare. S'il a deux armes identiques entre les mains, il aura un bonus d'attaque de 2 points.
      Barbarian olaf = new Barbarian("Olaf", 80, new Weapon("Mace", 5), new Weapon("Pique", 15));
      System.out.println(olaf.attack()); // 20
      Barbarian zorg = new Barbarian("Zorg", 75, new Weapon("Sword", 9), new Weapon("Sword", 9));
      System.out.println(zorg.attack()); // 20
      
    Ajouter également une méthode defense qui renvoie les points de défense d'un barbare, c'est à dire, pour l'instant, ses points de santé.

  5. Enfin, ajouter au barbare une méthode de combat fight qui prend un autre barbare en paramètre et qui affiche le nom du vainqueur (ou "nobody" en cas de match nul). Lors d'un combat, les deux opposants s'attaquent simultanément avec leurs armes (on retranche les point d'attaque de chacun aux point de défense de son adversaire), jusqu'à ce que les points de santé de l'un des deux tombent à 0, auquel cas il a perdu. Si cela arrive durant le même tour pour les deux barbares, il y a match nul. Attention, le combat ne modifie pas les points de santé des barbares (on imagine qu'ils se soignent après chaque combat).
    Notez que l'on ne veut afficher que l'issue du combat, pas son déroulement:
      hulk.fight(olaf); // Hulk won the fight!
      olaf.fight(zorg); // nobody won the fight!
      

  6. Certains barbares apprécient de pouvoir utiliser un bouclier pour se défendre plutôt qu'une arme.
    Un bouclier est une protection qui possède un nombre entier de points de défense. Écrire une classe Shield, ainsi que son constructeur qui prend en paramètre les points de défense. Ajouter le getteur correspondant.
    On doit également pouvoir afficher un bouclier:
        System.out.println(new Shield(50)); // Shield (50)
        

  7. On souhaite désormais que les barbares puissent équiper indifféremment des armes ou des boucliers (dans leurs mains). Pour cela, écrire une interface HandItem qui fournit les méthodes getDamage et getDefense que devront implémenter les armes et les boucliers.
    Modifier la classe Barbarian en conséquence. Pour calculer la défense d'un barbare, on ajoutera à sa santé les points de défense des éventuels boucliers qu'il tient dans les mains.

Exercice 2 - Le choix des armes

  1. Un barbare peut trouver des armes ou des boucliers sur son chemin et les rajouter à son inventaire représenté par une ArrayList de HandItem. Ajouter l'inventaire à la classe Barbarian et mettre à jour le code si nécessaire.

  2. Ajouter également une méthode addToInventory qui permet d'ajouter un item dans l'inventaire.
    Modifier le code pour pouvoir voir l'inventaire de la façon suivante lorsque l'on affiche un barbare:
      hulk.addToInventory(new Weapon("Club", 14));
      hulk.addToInventory(new Shield(61));
      hulk.addToInventory(new Weapon("Spear", 11));
    
      System.out.println(hulk);
      
      // Barbarian Hulk *100*, L : Dagger (8) , R : Axe (12) 
      // ------
      // Club (14) 
      // Shield (61) 
      // Spear (11) 
      // ------
       

  3. Enfin, ajouter deux méthodes swapLeftItem et swapRightItem qui prennent en paramètre un indice et permettent d'échanger le contenu de la main correspondante avec l'item rangé à cet indice dans l'inventaire. N'oubliez pas que si l’inventaire est vide, c'est que son état ne permet pas de faire l'échange et que vous vous n'avez pas le droit de choisir un indice hors de l'inventaire.
    Attention, vous devez toujours essayer de limiter au maximum la duplication de code!

Exercice 3 - L'extension rôdeurs

Désormais, les barbares pourront également croiser des rôdeurs sur le chemin.
  1. On va maintenant rajouter des rôdeurs (ranger en anglais) dans notre jeu. Un rôdeur a un nom, des points de santé, une arme (une seule) et un sort (représenté par un entier spell).
    Écrire une classe Ranger, ainsi que son constructeur qui prend en paramètre son nom et ses points de santé et qui place une arme dans sa main. Un rôdeur doit toujours avoir une arme, par contre il commence sa carrière sans connaître de sort (spell = 0).
    Faîtes en sorte que l'on puisse afficher un rôdeur avec le code suivant:
        Ranger ranger = new Ranger("Léon", new Weapon("Sword", 11), 130); 
        System.out.println(ranger); // Ranger Léon *130*, Sword (11), spell = 0
       
    L'affichage doit respecter le format de l'exemple ci-dessus.

  2. Ajouter une méthode learnNewSpell qui prend en paramètre un sort et permet au ranger de remplacer le sien par ce nouveau sort s'il est meilleur.
        ranger.learnNewSpell(4);
        System.out.println(ranger);   // Ranger Léon *130*, Sword (11), spell = 4 
        ranger.learnNewSpell(2);
        System.out.println(ranger);   // Ranger Léon *130*, Sword (11), spell = 4 
       

  3. On souhaite que les barbares et les rôdeurs puissent se battre entre eux. L'attaque d'un rôdeur est la somme des points de dégâts de son arme et de la valeur de son sort. Sa défense correspond à ses points de santé. Modifier votre code pour que les barbares et les rôdeurs puissent se battre entre eux. Le code suivant doit fonctionner (ainsi que les exemples précédents):
        ranger.fight(ranger);  // nobody won the fight!
        ranger.fight(olaf);    // Léon won the fight!
        hulk.fight(ranger);    // nobody won the fight!
        
    Dans la mesure du possible, vous ne devez pas dupliquer de code.

  4. En réalité, un barbare devrait toujours avoir au moins une arme dans les mains (et pas deux boucliers). Faîtes en sorte que sa main gauche contienne toujours une arme.
    Si vous pensez utiliser instanceof ou getClass pour cela, pensez plus fort...