Développement C# (.NET)

Développement C# (.NET)

Mis à jour le mardi 8 janvier 2013
  • Facile
Notions fondamentales

Travaux Pratique : le jeux de rôle

Bienvenue dans notre premier TP. Celui ci arrive plutôt tardivement car jusque là on ne pouvait pas vraiment faire de vrais travaux pratiques, seulement des petits exercices dissociés. Mais à présent que nous avons vu la POO, nous allons faire chauffer nos claviers pour créer le modèle d'un jeu de rôle. Si vous ne savez pas ce que signifie "modèle" en programmation, pas de panique, nous allons le voir avant de partir à l'aventure :pirate:

Enoncé

Pour ce premier TP, nous allons créer le modèle de données d'un petit jeu de rôle. Celui-ci ne révolutionnera pas le monde du jeu vidéo, mais vous fourniras un premier entrainement pratique en C#.

Qu'est ce qu'un modèle de données ?

Je vous ai parlé de "modèle de données", vous devez certainement vous demander ce que c'est et vous avez bien raison :D . Mais pour vous expliquez, je vais vous parler d'abord de patron de conception et d'architecture logicielle.
Plus généralement, chaque programme est souvent divisé en plusieurs parties, et l'architecture logicielle est l'interaction entre ces différentes parties. On parle alors d'architectures n-tiers où "n" est un nombre représentant le nombre de "parties".
De manière courante on utilise une architecture 3-tiers, c'est à dire, que lors de sa conception, notre programme va être créée en trois parties bien distinctes. Généralement il y aura une partie "vue" qui s'occupera seulement de l'affichage, une partie structure de données et une partie traitement. L'avantage c'est qu'entre les différentes parties il y a des interactions mais très peu de dépendances, c'est à dire que si par exemple nous modifions l'apparence de l'application nous devrons seulement modifier la partie "vue", ou si nous traitons différemment les données, la partie "vue" et la partie structure de données ne seront pas impactées.

Le modèle de données (ou "Model" en anglais) en architecture 3-tiers va être la partie structure de données citée un peu plus haut, c'est ce que nous allons créer dès à présent ;)

Énoncé

Pour votre premier modèle, on va faire bien, mais pas trop complexe ^^.
Il nous faudra créer deux types de personnages:

    Un héros qui aura

  • -Un nom

  • -Des points de vie

  • -Une position

  • -Une épée

    Celui ci pourra

  • -Attaquer un adversaire

  • -Recevoir des dégâts

  • -Faire une bonne action

  • -Se déplacer

Nous créerons aussi un monstre qui aura

  • -Un nom

  • -Des points de vie

  • -Une position

  • -Un gourdin

    Et celui ci pourra

  • -Attaquer un adversaire

  • -Recevoir des dégâts

  • -Se nourrir

  • -Se déplacer

Ensuite nous aurons deux types d'armes, l'épée et le gourdin.

    L'épée aura

  • -Un nom

  • -Des dégâts

  • -Une longueur

    Le gourdin aura

  • -Un nom

  • -Des dégâts

  • -Une masse

Et pour finir nous aurons besoin d'une classe Jeu qui ferra par la suite combattre nos deux joueurs. Elle devra donc avoir un héros et un ennemi.

Quelques conseils avant de démarrer

Ce n'est pas très compliqué, il suffit juste de bien se poser et de trouver ce que l'on doit représenter. Prenez pourquoi pas une feuille de papier ou notepad (ou notepad++ ^^) et essayez de noter les classes que vous devez faire (il peut ne pas y avoir exactement autant de classe que d'éléments que j'ai cité!! On peut très bien en faire plus qu'en faire moins). Une fois vos classes notées, essayez d'imaginer des éléments communs entre chacune, des classes abstraites ne peuvent pas faire de mal ;)

Ne vous cassez pas non plus la tête sur le contenu de vos méthodes, nous n'avons pas encore vu comment effectuer des traitements sur nos champs et nos objets, contentez vous d'imaginer les paramètres que prennent vos méthodes et ce qu'elles peuvent retourner, ensuite pour le contenu, affichez une simple message sur la console pour l'instant ;)

Bon, j'en ai assez dit, à vos claviers !!

Une correction

Les armes

Abstraction

Nous allons commencer par représenter l'épée et le gourdin, elles ont toute deux des champs communs : le nom et les dégâts. Nous allons donc commencer à créer une classe abstraite que nous nommerons par exemple "arme" avec un constructeur initialisant les deux champs :

public abstract class Arme
{
    #region Propriétés
    public string Nom { get; private set; } 

    public int Degats { get; private set; }
    #endregion

    #region Constructeur
    public Arme(string nom, int degats)
    {
        this.Nom = nom;
        this.Degats = degats;
    }
    #endregion
}

Ensuite nous faisons hériter cette classe dans deux autres classes : Epee et Gourdin :

Epee
public class Epee : Arme
{
    #region Propriétés
    public double Longueur { get;  private set; }
    #endregion

    #region Constructeur
    public Epee(string nom, int degats, double longueur)
        : base(nom, degats)
    {
        this.Longueur = longueur;
    }
    #endregion
}
Gourdin
public class Gourdin : Arme
{
    #region Propriétés
    public double Poids { get;  private set; }
    #endregion

    #region Constructeur
    public Gourdin(string nom, int degats, double poids):base(nom, degats)
    {
        this.Poids = poids;
    }
    #endregion
}

Remarquez ici que nous réutilisons même le constructeur de base que nous enrichissons en lui faisait prendre une paramètre de plus (longueur pour Epee et poids pour Gourdin).

Les personnages

Abstraction

Ici ce n'est pas moins de quatre champs et trois méthodes qui peuvent être abstraites entre le héros et le monstre. Pour la démonstration, une méthode est "normale", une méthode est virtuelle et une méthode est abstraite :

abstract class EtreVivant
{
    #region Propriétés
    public int PositionY { get; private set; }

    public int PositionX { get;  private set; }

    public string Nom { get;  private set; }

    public int PointsDeVie { get;  private set; }
    #endregion

    #region Constructeur
    public EtreVivant(string nom, int pointsDeVie)
    {
        this.Nom = nom;
        this.PointsDeVie = pointsDeVie;
    }
    #endregion

    #region Methodes
    public void SePositionner(int positionX, int positionY)
    {
        this.PositionX = positionX;
        this.PositionY = positionY;
    }

    public virtual void Attaquer(EtreVivant cible)
    {
        cible.RecevoirDegats(this);
    }

    public abstract void RecevoirDegats(EtreVivant source);
    #endregion
}

Vous pouvez remarquer ici que je n'ai même pas mis de corps à la méthode "RecevoirDegats" étant donné que nous serons obligé de lui fournir dans les classes héritières. Pour une méthodes sans corps, nous sommes obligés de remplacer les accolades par un point-virgule pour que le fichier de code passe la compilation.
Concernant la méthode "Attaquer", nous lui passons ici en paramètre un objet de type EtreVivant duquel nous appelons la méthode "RecevoirDegats", si vous n'avez pas fait pareil ce n'est pas grave, comme je vous l'ai dit, ce TP est fait pour s'entrainer à créer nos classes, les divers traitement que nous faisons ont pour l'instant peu d'importance ;)

Heros

Les seuls ajouts à faire ici sont l'Epee et la méthode "FaireUneBonneAction". Pour les autres méthodes, nous utilisons le mot-clé override pour les ré-implémenter.

class Heros : EtreVivant
{
    #region Proprietes
    public Epee Epee { get; private set; }
    #endregion

    #region Constructeur
    public Heros(string nom, int pointsDevie, Epee epee)
        : base(nom, pointsDevie)
    {
        Epee = epee;
    }
    #endregion

    #region Methodes
    public override void Attaquer(EtreVivant cible)
    {
        base.Attaquer(cible);
        Console.WriteLine("Le héros " + Nom + " attaque " + cible.Nom);
    }

    public override void RecevoirDegats(EtreVivant source)
    {
        Console.WriteLine(Nom + " s'est fait attaqué par " + source.Nom);
    }

    public void FaireUneBonneAction()
    {
        Console.WriteLine(Nom + " a fait une bonne action et en récompense, sa vie remonte ! ");
    }
    #endregion
}

Comme les implémentations de Arme, nous enrichissons le constructeur de base, mais cette fois-ci avec trois paramètres supplémentaires (nomArme, degatsArme et longueurEpee) et ensuite nous instancions la propriété "Epee" grâce aux paramètres précédemment récupérés.

Monstre

Pour la classe Monstre, il n'y pas de difficultés supplémentaires par rapport à Heros, on ajoute juste le champ et la méthode spécifique à Monstre :

class Monstre : EtreVivant
{
    #region Attributs
    public Gourdin Gourdin { get; private set; }
    #endregion

    #region Constructeur
    public Monstre(string nom, int pointDevie, Gourdin gourdin):base(nom, pointDevie)
    {
        Gourdin = gourdin;
    }
    #endregion

    #region Methodes
    public override void Attaquer(EtreVivant cible)
    {
        Console.WriteLine(Nom + " le gros monstre a attaqué " + cible.Nom);
    }

    public override void RecevoirDegats(EtreVivant source)
    {
        Console.WriteLine(Nom + " a reçu des dégâts de " + source.Nom);
    }

    public void SeNourrir()
    {
        Console.WriteLine(Nom + " se nourri et regagne de la santé");
    }
    #endregion
}

Classe Jeu

Pour finir, nous aurions pu éviter de créer cette classe et tout faire dans la classe Program. Mais en général, nous mettons le moins de code possible dans la classe Program et nous préférons créer une classe "de démarrage" à part.
Cette classe est surtout utile pour des traitements, mais étant donné que nous ne savons pas encore en faire, nous créerons juste deux champs et propriétés de type Monstre et Heros :

public class Jeu
{
    #region Attributs
    public Heros Gentil { get; private set; }

    public Monstre Ennemi { get; private set; }
    #endregion

    #region Constructeur
    public Jeu(Heros gentil, Monstre ennemi)
    {
        this.Gentil = gentil;
        this.Ennemi = ennemi;
    }
    #endregion
}

Même si lors de la compilation ce programme ne fait rien, nous avons déjà fait beaucoup : en effet comme je vous l'ai dit précédemment, dans tout programme vous aurez un modèle de données (plus ou moins important, certes) et la création de ce modèle de donnée est primordiale avant de réaliser les traitements.

Exemple de certificat de réussite
Exemple de certificat de réussite