Donjons et Dragons
Ce projet sert de pratique pour l'orienté objet, à savoir les classes, l'héritage, les interfaces et les classes abstraites. Nous allons donc simuler des personnages et des objets dans une partie de Donjons et Dragons et implémenter le tout en orienté objet.
Rien ne sert de tout planifier dès le début, des ajustements seront faits en cours de route.
Partie 1 - Classes
Débutons par implanter une classe pour les personnages. Les personnages devront avoir les attributs de base (force, dextérité, constitution, intelligence, sagesse et charisme), un nom, une classe, des points de vies et des points d'expérience.
Lorsqu'instancié, un personnage doit recevoir un nom et une classe. Une nouvelle instance peut également recevoir tous les attributs de base ou aucun. S'il n'en reçoit aucun, un nombre aléatoire entre 12 et 20 sera alors attribué.
Chaque personnage débute avec 40 points de vies.
À faire
- Créer une classe Personnage
- Permettre d'instancier avec un nom et une classe
- Permettre d'instancier avec un nom, une classe et les 6 attributs de base
- Remplacer la méthode
toString()pour afficher de l'information pertinence à propos de l'instance - Ajouter des
getterspour les statistiques, le nom et la classe - Créer une méthode
int gagnerExperience(int xp)qui ajoute la quantité d'expérience, affiche un message et retourne la nouvelle quantité d'expérience - Créer une méthode
int modifierVies(int vies)qui ajoute/supprime les points de vies, affiche un message et retourne la nouvelle quantité de points de vies. Attention, on peut gagner ou perdre des points de vies!
- Tester le jeu
- Créer deux personnages, chacun avec un constructeur différent, et les ajouter dans un
ArrayList<Personnage> - Modifier les vies et les points d'expérience pour chacun des personnages
- Afficher les personnages à l'aide d'une boucle
for (Personnage p : personnages)
- Créer deux personnages, chacun avec un constructeur différent, et les ajouter dans un
Solution
Solution
import java.util.ArrayList;
public class Jeu {
static void main() {
ArrayList<Personnage> personnages = new ArrayList<>();
// Les personnages
Personnage sorcier = new Personnage("Melchior", "Sorcier");
Personnage guerrier = new Personnage("Therion", "Guerrier", 20, 19, 18, 10, 10, 12);
personnages.add(sorcier);
personnages.add(guerrier);
// Faire des actions
guerrier.gagnerExperience(5);
sorcier.modifierVies(-3);
guerrier.modifierVies(7);
// Afficher les personnages
for (Personnage p : personnages) {
System.out.println(p);
}
}
}
import java.util.Random;
public class Personnage {
// Nom et classe
private String nom;
private String classe;
// Les statistiques
private int force;
private int dexterite;
private int constitution;
private int intelligence;
private int sagesse;
private int charisme;
private int experience = 0;
private int vies = 40;
public Personnage(String nom, String classe, int force, int dexterite, int constitution, int intelligence, int sagesse, int charisme) {
this.nom = nom;
this.classe = classe;
this.force = force;
this.dexterite = dexterite;
this.constitution = constitution;
this.intelligence = intelligence;
this.sagesse = sagesse;
this.charisme = charisme;
}
public Personnage(String nom, String classe) {
this.nom = nom;
this.classe = classe;
// Générer les statistiques de manière aléatoire
Random random = new Random();
this(nom, classe, random.nextInt(12, 20),random.nextInt(12, 20),random.nextInt(12, 20),random.nextInt(12, 20),random.nextInt(12, 20),random.nextInt(12, 20));
}
public int gagnerExperience(int xp) {
System.out.printf("** %s gagne %d points d'expérience%n", this.nom, xp);
this.experience += xp;
return this.experience;
}
public int modifierVies(int vies) {
if (vies > 0) {
System.out.printf("** %s gagne %d points de vies%n", this.nom, vies);
} else if (vies < 0) {
System.out.printf("** %s perd %d points de vies%n", this.nom, vies*-1);
}
this.vies += vies;
return this.vies;
}
public String getNom() {
return nom;
}
public String getClasse() {
return classe;
}
public int getForce() {
return force;
}
public int getDexterite() {
return dexterite;
}
public int getConstitution() {
return constitution;
}
public int getIntelligence() {
return intelligence;
}
public int getSagesse() {
return sagesse;
}
public int getCharisme() {
return charisme;
}
@Override
public String toString() {
return String.format("%s (%s - %d xp) : %d vies",
this.nom, this.classe, this.experience, this.vies);
}
}
Partie 2 - Héritage
Étant donné que Donjons et Dragons possède une quantité définie de classe de personnages, il pourrait être intéressant de les représenter sous forme d'objet qui hériterons de la classe Personnage.
- Le sorcier est un personnage. En plus des actions d'un personnage, il pourra également lancer un sort.
- L'archer est aussi un personnage. En plus des actions d'un personnage, il pourra également tirer des flèches.
- Finalement, le guerrier, en plus des actions d'un personnage, gagne 2 fois plus d'expérience que les autres.
À faire
- Créer les nouvelles classes
- Créer une classe
Sorcieret ajouter la méthodevoid lancerSort(String sort)qui affiche un message. - Créer une classe
Archeret ajouter la méthodevoid tirerFleches()qui affiche un message. - Créer une classe
Guerrieret remplacer la méthodeint gagnerExperience(int xp)pour ajuster son gain d'expérience.
- Créer une classe
- Tester les nouvelles classes
- Créer une instance pour le sorcier, l'archer et le guerrier et les ajouter dans le
ArrayList<Personnage>. - Tester les méthodes
lancerSort()ettirerFleches() - Faire gagner 5 points d'expérience à tous à l'aide d'une boucle
for
- Créer une instance pour le sorcier, l'archer et le guerrier et les ajouter dans le
Solution
Solution
Aucun changement
public class Sorcier extends Personnage {
public Sorcier(String nom, int force, int dexterite, int constitution, int intelligence, int sagesse, int charisme) {
super(nom, "Sorcier", force, dexterite, constitution, intelligence, sagesse, charisme);
}
public Sorcier(String nom) {
super(nom, "Sorcier");
}
public void lancerSort(String sort) {
System.out.printf("** Le sorcier %s lance le sort %s%n", this.getNom(), sort);
}
}
public class Archer extends Personnage {
public Archer(String nom, int force, int dexterite, int constitution, int intelligence, int sagesse, int charisme) {
super(nom, "Archer", force, dexterite, constitution, intelligence, sagesse, charisme);
}
public Archer(String nom) {
super(nom, "Archer");
}
public void tirerFleche() {
System.out.printf("** L'archer %s tire une flèche%n", this.getNom());
}
}
public class Guerrier extends Personnage {
public Guerrier(String nom, int force, int dexterite, int constitution, int intelligence, int sagesse, int charisme) {
super(nom, "Guerrier", force, dexterite, constitution, intelligence, sagesse, charisme);
}
public Guerrier(String nom) {
super(nom, "Guerrier");
}
@Override
public int gagnerExperience(int xp) {
return super.gagnerExperience(xp * 2);
}
}
import java.util.ArrayList;
public class Jeu {
static void main() {
ArrayList<Personnage> personnages = new ArrayList<>();
// Les personnages
Sorcier sorcier = new Sorcier("Melchior");
Archer archer = new Archer("Kellan");
Guerrier guerrier = new Guerrier("Therion");
personnages.add(sorcier);
personnages.add(archer);
personnages.add(guerrier);
// Faire des actions
sorcier.lancerSort("Malédiction");
archer.tirerFleche();
// Gagner l'expérience
for (Personnage p : personnages) {
p.gagnerExperience(5);
}
// Afficher les personnages
for (Personnage p : personnages) {
System.out.println(p);
}
}
}
** Le sorcier Melchior lance le sort Malédiction
** L'archer Kellan tire une flèche
** Melchior gagne 5 points d'expérience
** Kellan gagne 5 points d'expérience
** Therion gagne 10 points d'expérience
Melchior (Sorcier - 5 xp) : 40 vies
Kellan (Archer - 5 xp) : 40 vies
Therion (Guerrier - 10 xp) : 40 vies
Partie 3 - Interfaces
Maintenant, nous devons ajouter des objets à détruire : une boîte. Une boîte n'est pas un personnage mais aura également des points de vies et pourra être détruite, ce que les personnages et la boîte ont en commun. Une interface sera donc un ajout idéal pour les points de vies. Finalement, on pourra ajuster la classe Personnage pour ajuster le tout et tester notre jeu.
À faire
- Créer une classe
IDestructiblequi forcera l'implémentation de deux méthodes :int getPointsDeVies();--> Obtenir les points de vies de l'objetint modifierVies(int vies);--> Modifier les points de vies de l'objet
- Créer une classe
Boitequi implémente l'interface, lui attribuer 10 points de vie et coder la modification de points de vies - Ajouter tous les personnages et la boîte dans un nouvel
ArrayList<IDestructible> - Ajuster la classe
Personnagepour implémenter l'interface. - Étant donné que les personnages ont (habituellement) des équipements, ajuster la méthode
modifierVies()afin de perdre 1 point de vie de moins en tout temps - Ajuster la classe
Guerrierafin qu'il perde 2 points de vie de moins en tout temps - Tester le jeu en ajoutant les actions suivantes :
- Un malus fait perdre 3 points de vie à tout ce qui est destructible sur le plateau de jeu. Effectuer l'action à l'aide d'une boucle
for (IDestructible destructible : destructibles) - Un sort lancé fait perdre 3 points de vie à tout ce qui est destructible et qui n'est pas un personnage. Effectuer également à l'aide d'une boucle, d'une condition et de l'instruction
instanceof
- Un malus fait perdre 3 points de vie à tout ce qui est destructible sur le plateau de jeu. Effectuer l'action à l'aide d'une boucle
Solution
Solution
public class Boite implements IDestructible {
private int vies = 10;
@Override
public int getPointsDeVies() {
return this.vies;
}
@Override
public int modifierVies(int vies) {
this.vies += vies;
if (this.vies <= 0) {
System.out.println("** La boite est détruite");
} else {
System.out.printf("** La boite a encore %d points de vies%n", this.vies);
}
return 0;
}
}
import java.util.Random;
public class Personnage implements IDestructible {
...
@Override
public int getPointsDeVies() {
return this.vies;
}
@Override
public int modifierVies(int vies) {
if (vies > 0) {
System.out.printf("** %s gagne %d points de vies%n", this.nom, vies);
} else if (vies < 0) {
// Perdre un point de vie de moins
vies = vies + 1;
System.out.printf("** %s perd %d points de vies%n", this.nom, vies*-1);
}
this.vies += vies;
return this.vies;
}
...
}
** Le sorcier Melchior lance le sort Malédiction
** L'archer Kellan tire une flèche
** Melchior gagne 5 points d'expérience
** Kellan gagne 5 points d'expérience
** Therion gagne 10 points d'expérience
MALUS
** Melchior perd 2 points de vies
** Kellan perd 2 points de vies
** Therion perd 1 points de vies
** La boite a encore 7 points de vies
SORT DE FEU
** La boite est détruite
Melchior (Sorcier - 5 xp) : 38 vies
Kellan (Archer - 5 xp) : 38 vies
Therion (Guerrier - 10 xp) : 39 vies
Partie 4 - Classe abstraite
Finalement, nous allons ajouter des ennemis avec une classe abstraite (abstract). Cette classe sera incomplète et il faudra la compléter à chaque nouvelle implémentation d'un ennemi. Comme un ennemi est aussi destructible, il devra implémenter l'interface IDestructible.
Un ennemi possède un nom et des points de vies. Il pourra aussi attaquer un personnage grace à une valeur d'attaque, à spécifier.
À faire
- Créer une classe abstraite
Ennemiqui implémenteIDestructible. - Remplacer la méthode
toString()pour un message efficace. - Créer le constructeur qui accepte un nom et des points de vies de départ.
- Créer une méthode abstraite
int getValeurAttaque(), qui devra être implémentée par les classes enfants - Créer une méthode
void attaquer(Personnage p)qui attaque le personnagepen utilisant la méthodegetValeurAttaque() - Créer une classe
Goblinqui hérite de la classeEnnemi. De plus, il devra remplacer certaines méthodes :getValeurAttaque(): Le goblin possède 10 points de vies et effectue 2 dégatsmodifierVies(): Le goblin subit 2 fois les dégats habituels
- Modifier le jeu pour :
- Créer un goblin et l'ajouter dans la liste
destructibles - Créer un nouvel ennemi "Mort-Vivant" directement dans le jeu (
Ennemi mortVivant = new Ennemi(...)) et implémenter la méthode abstraite. Le mort-vivant possède 7 points de vies et attaque de 2 fois ses points de vies - Tous les ennemis doivent attaquer l'archer. Utiliser une boucle
foret vérifier pour l'instanceEnnemi.
- Créer un goblin et l'ajouter dans la liste
Solution
Solution
public abstract class Ennemi implements IDestructible {
private String nom;
protected int vies;
public abstract int getValeurAttaque();
public Ennemi(String nom, int vies) {
this.nom = nom;
this.vies = vies;
}
@Override
public int getPointsDeVies() {
return this.vies;
}
@Override
public int modifierVies(int vies) {
System.out.printf("** L'ennemi %s perd %d vies%n", this.nom, -vies);
return this.vies += vies;
}
public void attaquer(Personnage p) {
System.out.printf("** %s attaque %s de %d%n", this.nom, p.getNom(), this.getValeurAttaque());
}
@Override
public String toString() {
return "Ennemi (%s) : %d".formatted(this.nom, this.getPointsDeVies());
}
}
public class Goblin extends Ennemi {
public Goblin() {
super("Goblin", 10);
}
@Override
public int getValeurAttaque() {
return 2;
}
@Override
public int modifierVies(int vies) {
int doubleVies = vies * 2;
System.out.printf("** Le goblin perd le double : %d%n", -doubleVies);
return this.vies += -doubleVies;
}
}
** Le goblin fait 2 dégats à Kellan
** Kellan perd 1 points de vies
** Mort-Vivant attaque Kellan de 14
** Le sorcier Melchior lance le sort Malédiction
** L'archer Kellan tire une flèche
** Melchior gagne 5 points d'expérience
** Kellan gagne 5 points d'expérience
** Therion gagne 10 points d'expérience
MALUS
** Melchior perd 2 points de vies
** Kellan perd 2 points de vies
** Therion perd 1 points de vies
** La boite a encore 7 points de vies
** Le goblin perd le double : 6
** L'ennemi Mort-Vivant perd 3 vies
SORT DE FEU
** La boite est détruite
** Le goblin perd le double : 20
** L'ennemi Mort-Vivant perd 10 vies
Melchior (Sorcier - 5 xp) : 38 vies
Kellan (Archer - 5 xp) : 37 vies
Therion (Guerrier - 10 xp) : 39 vies