Modding d'Hytale
Bases de Java

07 - Introduction à la Programmation Orientée Objet

Apprenez les fondamentaux des classes et objets en Java.

La programmation orientée objet (POO) est la base de Java et du modding d'Hytale. Au lieu d'avoir uniquement des variables et des méthodes éparpillées, nous les organisons en Classes et en Objets.

Qu'est-ce qu'une Classe ?

Une classe est un plan pour la création d'objets. Imaginez-le comme une recette ou un modèle.

public class Joueur {
    // Propriétés (données)
    String nom;
    int vie;
    int niveau;
    
    // Comportement (méthodes)
    public void subirDegats(int degats) {
        vie -= degats;
        System.out.println(nom + " à pris " + degats + " dégâts !");
    }
}

Qu'est-ce qu'un Objet ?

Un objet est une instance crée à partir d'une classe. Si une classe est un plan, un objet est la chose concrète créée à partir de ce plan.

public class Main {
    public static void main(String[] args) {
        // Créer des objets de la classe Joueur
        Joueur joueur1 = new Joueur();
        joueur1.name = "Alice";
        joueur1.health = 100;
        joueur1.level = 5;
        
        Joueur joueur2 = new Joueur();
        joueur2.name = "Bob";
        joueur2.health = 80;
        joueur2.level = 3;
        
        // Use the objects
        joueur1.subirDegats(20);  // Alice à pris 20 dégâts !
        joueur2.subirDegats(15);  // Bob à pris 15 dégâts !
    }
}
Classe vs Objet

Classe = Plan (l'idée d'un joueur) Objet = Chose concrète (Alice, Bob, des joueurs spécifiques)

Une classe peut créer plusieurs objets, au même titre qu'une recette peut faire plusieurs gâteaux !

Créer une Classe simple

Créons une classe Epee pour Hytale :

public class Epee {
    // Propriétés
    String nom;
    int degats;
    int durabilite;
    
    // Methode pour utiliser l'épée
    public void attaquer(String cible) {
        System.out.println("Attaque " + cible + " pour " + degats + " dégâts !");
        durabilite -= 1;
        
        if (durabilite <= 0) {
            System.out.println(nom + " s'est cassée !");
        }
    }
    
    // Methode pour afficher les informations
    public void afficherInfo() {
        System.out.println("Arme : " + nom);
        System.out.println("Dagâts : " + degats);
        System.out.println("Durabilité : " + durabilite);
    }
}

Utilisons la classe :

public class Main {
    public static void main(String[] args) {
        Epee epee = new Epee();
        epee.nom = "Iron Sword";
        epee.degats = 15;
        epee.durabilite = 3;
        
        epee.afficherInfo();
        epee.attaquer("Zombie");
        epee.attaquer("Skeleton");
        epee.attaquer("Spider");  // Cela va casser l'épée
    }
}

Constructeurs

Au lieu de définir les propriétés une par une, utilisez un constructeur pour initialiser les objets :

public class Epee {
    String nom;
    int degats;
    int durabilite;

    // Constructeur
    public Epee(String nomArme, int degatsArme, int durabiliteArme) {
        nom = nomArme;
        degats = degatsArme;
        durabilite = durabiliteArme;
    }

    public void attaquer(String cible) {
        System.out.println("Attaque " + cible + " pour " + degats + " dégâts !");
        durabilite--;
    }
}

Maintenant créer des épées est plus facile :

public class Main {
    public static void main(String[] args) {
        // Plus propre !
        Epee epeeEnFer = new Epee("Épée en Fer", 15, 100);
        Epee epeeEnDiamant= new Epee("Épée en Diamant", 25, 200);
        
        epeeEnFer.attaquer("Zombie");
        epeeEnDiamant.attaquer("Boss");
    }
}
Règles du constructeur
  • Même nom que la classe
  • Pas de type de retour (pas même void)
  • Appelé automatiquement lorsque vous faites new
  • Il est possible d'avoir plusieurs constructeurs (surcharge)
public class Objet {
    String nom;
    int valeur;
    
    // Constructeur avec tous les paramètres
    public Objet(String nom, int valeur) {
        this.nom = nom;
        this.valeur = valeur;
    }
    
    // Constructeur avec seulement le nom
    public Objet(String nom) {
        this.nom = nom;
        this.valeur = 0;  // Valeur par défaut
    }
}

Le mot clé this

this fait référence à l'objet courant. Utilisez-le pour clarifier lorsque les noms des paramètres équivalent aux noms des propriétés

public class Joueur {
    String nom;
    int vie;
    
    public Objet(String nom, int vie) {
        this.nom = nom; // this.nom : la propriété, nom : le paramètre
        this.vie= vie; // this.vie : la propriété, vie : le paramètre
    }
}

Sans this Java serait confus :

public Joueur(String nom, int vie) {
    nom = nom;      //Quel nom ? Ambiguë !
    vie = vie;  //Quelle vie ? Ambiguë !
}

Exemples pratiques

Classe Objet

public class Objet {
    String nom;
    String type;
    int quantite;
    double poid;
    
    public Objet(String nom, String type, int quantite, double poid) {
        this.nom = nom;
        this.type = type;
        this.quantite = quantite;
        this.poid = poid;
    }
    
    public void utiliser() {
        if (quantite > 0) {
            quantite--;
            System.out.println("Utilisé " + nom + ". Restant : " + quantite);
        } else {
            System.out.println("Aucun " + nom + " restant !");
        }
    }
    
    public double obtenirPoidTotal() {
        return poid * quantite;
    }
}
public class Main {
    public static void main(String[] args) {
        Objet potion = new Objet("Potion de soin", "Consommable", 5, 0.5);
        
        potion.utiliser();  // Utilisé Potion de soin. Restant : 4
        System.out.println("Poid total : " + potion.obtenirPoidTotal()); // 2.0
    }
}

Classe Monstre

public class Monstre {
    String nom;
    int vie;
    int attaque;
    boolean estHostile;
    
    public Monstre(String nom, int vie, int attaque, boolean estHostile) {
        this.nom = nom;
        this.vie = vie;
        this.attaque = attaque;
        this.estHostile = estHostile;
    }
    
    public void subirDegats(int degats) {
        vie -= degats;
        System.out.println(nom + " à pris " + degats + " dégâts !");
        
        if (vie <= 0) {
            System.out.println(nom + " was defeated!");
        } else {
            System.out.println(nom + " a " + vie + " points de vie restant.");
        }
    }
    
    public int attaquerJoueur() {
        if (estHostile && vie > 0) {
            System.out.println(nom + " attaque pour " + attaque + " dégâts !");
            return attaque;
        }
        return 0;
    }
    
    public boolean estEnVie() {
        return vie > 0;
    }
}
public class Main {
    public static void main(String[] args) {
        Monster zombie = new Monstre("Zombie", 50, 10, true);
        Monster poulet = new Monstre("Poulet", 10, 0, false);
        
        zombie.subirDegats(20);        // Zombie à pris 20 dégâts !
        int degats = zombie.attaquerJoueur();  // Zombie attaque pour 10 dégâts !
        
        if (zombie.estEnVie()) {
            System.out.println("Monstre est toujours en vie !");
        }
    }
}

Classe Bloc

public class Bloc {
    String type;
    int x, y, z;
    boolean estSolide;
    int durete;
    
    public Bloc(String type, int x, int y, int z, boolean estSolide, int durete) {
        this.type = type;
        this.x = x;
        this.y = y;
        this.z = z;
        this.estSolide = estSolide;
        this.durete = durete;
    }
    
    public void casserBloc() {
        System.out.println("J’ai cassé le bloc " + type + " en (" + x + ", " + y + ", " + z + ")");
        System.out.println("Durete : " + durete);
    }
    
    public String obtenirPosition() {
        return "(" + x + ", " + y + ", " + z + ")";
    }
    
    public boolean peutMarcherATravers() {
        return !estSolide;
    }
}

Modificateurs d'accès (Aperçu)

Vous avez pu voir public - Cela signifie "Tout le monde peut y accéder". Nous en apprendrons plus sur le contrôle d'accès plus tard, mais voici un aperçu :

public class Exemple {
    public String varPublique;      // Tout le monde y a accès
    private String varPrivee;    // Seulement cette classe y a accès
    /* (no modifier) */ String varDefaut; // Accès dans le package seulement
}

Pour l'instant, utilisez public pour tout. Nous apprendrons quand utiliser private dans le prochain article.

Pourquoi utiliser des Classes ?

Les classes vous aident :

  • Organiser les données et méthodes qui vont ensemble
  • Réutiliser du code facilement (créer plusieurs objets à partir d'une classe)
  • Modéliser des choses du monde réel (joueurs, objets, monstres)
  • Maintenir le code (des changements à un endroit affectent tous les objets)

Sans classes, gérer 100 joueurs nécessiterait 100 variables distinctes pour chaque propriété. Avec des classes, c'est juste 100 objets Joueur !

Exercices pratiques

  1. Créez une classe Potion :

    • Propriétés : nom, valeurDeSoin, utilisations
    • Un constructeur pour définir toutes les propriétés
    • Une méthode boire() qui soigne et fait baisser le nombre d'utilisations restantes
    • Une méthode estVide() qui retourne vrai si les utilisations restantes sont inférieures ou égales à 0
  2. Créez une classe Coffre :

    • Propriétés : estFerme, nombreObjets, capacite
    • Un constructeur
    • Une méthode ajouterObjet() qui vérifie la capacité
    • Une méthode debloquer() qui met estFerme à faux
    • Une méthode estPlein() qui vérifie si nombreObjets est >= à capacite
  3. Créez une classe Villageois :

    • Propriétés : nom, profession, nombreDeTransactions
    • Un constructeur
    • Une méthode saluer() qui affiche une salutation
    • Une méthode echange() qui augmente le nombreDeTransactions
    • Une méthode obtenirInfos() qui affiche toutes les propriétés
  4. Créez plusieurs Objets : en utilisant les classes que vous avez créées, instanciez trois objets et testez toutes leurs méthodes.