*
Pong objet

Objet, un gros mot de la programmation qui se révèle assez facile et intuitif à comprendre. Seule difficulté : la conceptualisation (hm! c'est juste un peu le coeur du pbm!).

Programmation objet ?
Commencer par les concepts fondamentaux, les notions, le vocabulaire et un exemple Joueur, pour comprendre.

Note préliminaire : bien lire le texte, les notions et le vocabulaire utilisé ici sont important dans la description des concepts de la programmation objet.

 

Déjà vu

Pour enregistrer les coordonnées du curseur de Pong, les dimensions de l'écran, la vitesse de la balle, nous avons utilisé un type de données particulier.

En effet, les types simples sont int, String, float, boolean, et autre char.

Un vecteur est un couple de valeurs de type float : x et y.

On accède à l'une des valeurs en mettant un point derrière le nom de la variable suivi du nom de la valeurs à chercher.

exemple :

Source exemple 1

 

Ce type d'objet est appelé classe d'objet.

Pour créer une variable objet de cette classe d'objet, on utilisera la notation suivante (remarquer la majuscule convetionnellement donnée au nom de la classe) :

Source exemple 2

Créer une variable de type objet est dit 'instancier un objet'.

 

Créons, créons, créons

Créer des nouvelles classe d'objet est assez simple.

On définit le nom de la classe avec le mot ... class (en minuscules) suivi du nom de la classe à créer.

Source

Puis les attributs (variables internes)

Source

Ces attributs peuvent êtres publiques (public) et accessible directement, ou privés (private) et nécessiter une méthode spécialement écrite pour les modifier.

Dans Processing, si rien n'est indiqué, les attributs sont publiques et accessibles.

 

Et enfin, les "méthodes" (fonctions que l'on peut faire avec un objet)

Source

De la rigueur, que diable !

Pour les méthodes, le plus "propre" est de ne plus utiliser de variables globales mais des paramètres transmis aux méthodes selon les besoins (revoir la notion de surchage dans pong 1, procédural).

 

Primo methodis

Au moment de l'instanciation (création de l'objet), l'ordinateur appelle une méthode précise qui porte le nom de la classe.
Il s'agit du constructeur.
Cette méthode n'est appelée qu'une seule fois, comme setup(), et sert à initialiser un objet.

C'est très, très pratique. Il faudra soigner sa rédaction car elle permet d'exécuter du code complexe qu'une seule fois dans l'exécution du programme et de ranger proprement le code de l'application.

 

Exemple concret : ébauche de la classe Joueur dans notre jeu Pong

Important : un joueur est représenté par son score, la position de l'affichage de celui-ci, la position de son curseur.

On peut incrémenter le score, déplacer le curseur, afficher le score, afficher le curseur du joueur 1 ou 2, selon l'objet Joueur appelé.

Source

 

Les modifications consécutives seront les suivantes :

  • création des objets j1 et j2,
  • utilisation de la méthode inc() pour incrémenter le score et
  • utilisation de l'attribut score de chaque joueur pour l'afficher :

Observer les modifs dans le code suivant ( marquées par >o<)

Source

 

Et voilà. Maintenant, on n'a plus besoin de déclarer j1_score ni j2_score, c'est fait automatiquement à la déclaration des objets j1 et j2.

Pong objet ?
Aller plus loin, étoffer la classe Joueur.

Maintenant qu'on a vu l'essentiel, passons à la pratique et étoffons la classe Joueur avant de les étouffer (ou de s'étouffer soi-même ...).

 

Méthodes de collecte

Alors, un joueur ne se résume pas à un score. On va lui rajouter la position d'affichage de son tableau de chasse (l'affichage du score) et son curseur (c'est le sien, pas celui de l'autre, là bas, de l'autre coté du terrain !! ksss, ksss).

Un joueur :

  • Possède un score (attribut),
  • Possède un coté (1 ou -1 = gauche ou droit),
  • Possède une position d'affichage de son score (définie selon son coté),
  • Possède un curseur donné par sa position (défini selon le coté),
  • On peut incrémenter le score (nouvelle méthode),
  • On peut afficher le score (méthode reprise de la fonction score_draw()),
  • On peut déplacer le curseur (méthode reprise de la fonction curseur_move()),
  • On peut afficher le curseur (méthode reprise de la fonction curseur_draw()),

Ce qui est bien, c'est qu'on n'a plus besoin de transmettre les valeurs originales, on y accède directement dans l'objet.

Explications :

L'ancienne fonction score_draw avait deux paramètres : dix (position d'affichage) et score (valeur à afficher).

la nouvelle méthode score_draw n'en n'a plus besoin, elle appartient à l'objet et peut donc utiliser les deux anciens paramètres sans les demander. ils correspondront bien à l'objet (joueur) concerné.

Pas mal, non ? Ainsi on simplifie le code. on ne voit que l'appel à la méthode. Celle-ci fera le boulot qu'on lui demande avec les bonnes données.

 

Et voici la saison 1 du code complet de la classe Joueur :

La puissance du constructeur
Tout est dans le titre.

On disait plus haut que le constructeur est bien pratique, mais on ne savait pas à quel point.

 

En fait, avec la classe précédente, il faut instancier l'objet joueur puis déclarer les différentes valeurs des attributs.

C'est idiot, cela complique le code comme ci-dessous dans la fonction setup() ...

Source

On va donc créer un constructeur qui fera ce boulot automatiquement lors de l'instanciation de l'objet et la fonction setup redeviendra beaucoup plus simple (Yeah, j'aime ce qui est simple!).

Voici donc le code du constructeur, ...

Source

... Et le nouveau code de setup() (tiens ? ça ressemble au code avant de parler d'objet !?!!),

Source

 

C'est y pas mieux, ça ??? C'est ben vrai, ça, mère Denis! (vous n'avez pas compris l'allusion?, c'est normal, c'est un truc de vieux! un p'tit coup de youtube et vous trouverez... c'est relou (& chelou itou) mais ça fait du bien).

 

Et voici la saison 2 du code complet de la classe Joueur (encore amélioré par rapport à la version précédente) :

 

Et le code complet de du programme est disponible ci-dessous.

Pour en finir, diviser pour mieux régner
Faire plusieurs fichiers pour simplifier l'écriture. Les fichiers seront réutilisables dans d'autres aventures de programmation.

Petit jeu : Avant d'abattre l'auteur, celui-ci a dispersé ses codes sources dans plusieurs fichiers différents afin de "simplifier" la lecture.

  • Séparation de la classe Joueur pour gérer le joueur, elle demande la classe Digit
  • Création de la classe Balle, pour gérer la balle et ses rebonds sur des obstacles (bord, joueur),
  • Création de la classe Digit pour afficher un digit

A vous de reconstituer le puzzle.

Par ailleurs, certaines méthodes ont été fusionnées (score_draw et curseur_draw) et on a séparé les deux digits (transformés en objets) pour une initialisation plus rapide.

Tout est dit dans les fichiers sources suivants (version 8 et fin de Pong, parce que j'en ai assez de ce *@###$$!! de programme).

Remarques de post-production : tous les sources "doivent" être dans un répertoire portant le nom du code mâitre.

Critique (faible) : la classe Balle ne devrait théoriquement pas interragir directement avec les joueurs, mais on devrait peut-être avoir une classe jeu (ce qui complique plus encore l'abstraction qu'elle n'est déjà ...).

Bon, il est l'heure de ma camomille ... bonne nuit.