Objectif :
Définir un système de notation permettant de décrire de façon non-ambiguë tout enchaînement de figures de pen spinning. Cette notation doit rendre aisée la description d’une figure à une personne donnée, et elle doit pouvoir de plus être évolutive, c’est-à-dire être aisément modifiable et améliorable.
Forme :
J’ai choisi d’écrire cette notation sous la forme d’un langage de programmation. Deux raisons à cela : un langage de programmation est par essence même non-ambigu, en ce qu’il peut être interprété par une machine. De plus, cette forme permet théoriquement la création d’un interprétateur de ce langage, sous la forme d’un logiciel qui prendrait un programme de type « combo » en entrée et donnerait en sortie, soit un descriptif « lisible » du combo, soit une vidéo montrant le combo – ladite vidéo n’ayant pas pour but de ressembler à une vidéo réelle, mais plutôt à une suite saccadée de mouvements aisés à distinguer et à reproduire qui, mis fluidement bout à bout par l’utilisateur, redonneraient le combo complet.
NB : ce langage n’a en aucun cas pour but de mettre en évidence la manière dont on doit exécuter les tricks. Seule la trajectoire du mod et les mouvements de main faisant partie du trick sont décrits ; les moyens de réaliser concrètement le trick, en tenant compte de la gravité par exemple, ne sont pas pris en compte. Typiquement, dans la description formelle d’un bust, le mouvement de poignet est négligé.
Qu’est ce que l’orienté objet ?
La programmation orienté objet est un type de langage de programmation. Elle s’oppose par exemple à la programmation impérative (le C,…) dans laquelle un programme principal fait appel à des sous-programmes définissant des fonctions à utiliser. La programmation orientée objet fonctionne d’une manière bien plus adaptée au PS : on créé des objets qui communiquent entre eux et interagissent par envoi de message. L’idée est donc très simple : utiliser ce type de programmation et créer des objets comme « la main » et « le mod » qui interagiront. Ce système permet donc de modéliser informatiquement un combo.
Je me suis fortement inspiré du langage JAVA, simplement parce que je le connais, mais ce que j’ai conçu n’est bien évidemment pas du JAVA : ce dernier n’est pas adapté à la notation d’un combo, de toute évidence.
Détaillons un peu plus l’orienté objet : des répertoires, appelés « package » contiennent des classes. Qu’est-ce qu’une classe ? C’est là que ça devient un peu plus technique : une classe est une « idée d’objet ». Je pense qu’un exemple peut aider à comprendre : si je créé la classe « main », j’aurais créé d’une certaine façon l’idée de l’objet main. Cette classe décrit ce qu’est une main : c’est un objet possédant une paume, un dos, 5 doigts, ces derniers pouvant saisir des objets…
Comment utiliser cette classe ? En l’instanciant. Je dispose du « schéma général de la main », sous la forme de la classe « main », et je vais donc créer un nouvel objet de type main : je déclare que cet objet est une main (« main » étant donc défini par la classe associée), et j’entre les caractéristiques de mon objet précis (par exemple, je pourrais préciser si c’est une main droite ou gauche, la longueur des doigts, etc…). Un objet, donc, c’est une classe qui a été instanciée.
Que contient une classe ? Une classe contient deux choses, qui suffisent à décrire tous les objets qu’elle définit :
-Des attributs, qui sont en quelque sorte ses caractéristiques
-Des méthodes, qui définissent ce que la classe peut faire. On peut aussi associer une méthode à un package.
Dans la classe, les attributs sont des variables : on leur affectera une valeur précise au moment d’instancier la classe, c'est-à-dire de créer un objet à partir de cette classe.
Exemple :
Classe « mod » :
Attributs : longueur, single sided ou double sided, longueur du corps, position du COG, largeur du corps, largeur des caps, longueur de la partie grippée, poids
Méthode : tourner ; cette méthode prend en entrée un angle et un sens de rotation
Maintenant, je vais créer un objet de type « mod » qui correspondra à un rsvp mx :
Rsvp_mx = new mod(18cm, single sided, 12cm, COP+0.5cm, 1cm, 1.1cm, 3cm, 14g) (données mises un peu au pif, bien sûr).
Et si je veux faire tourner mon rsvp mx de 180° dans le sens des aiguilles d’une montre :
Rsvp_mx.tourner(180°, CW)
Voilà pour le principe de l’orienté objet appliqué au pen spinning. Je vais maintenant définir précisément les packages, classes, méthodes, attributs et opérateurs à partir desquels j’estime pouvoir noter à peu près n’importe quel combo.
Packages et classes :
Je choisis de disposer de deux packages : h (pour « hand ») et m (pour « mod »). Oui, ici h et m sont des répertoires, et non plus des classes. Après réflexion, ça m’a paru plus pratique ainsi.
Package h :
Class Palm(direction)
Class Fingeri(position) => ici, remplacer I successivement par 1, 2, 3, 4 ou T.
Class BackHand(direction)
Mon répertoire h contient donc 7 classes : la paume, qui prend en entrée une direction (up, down, right side, left side) ; les 5 doigt, qui prennent en entrée une position (folded ou unfolded) ; le dos de la main, qui prend en entrée une direction.
Au moment de créer un objet, il est possible d’en préciser les attributs, mais ce n’est pas obligatoire.
Exemples :
Paume1 = new Palm() : Je créé un objet de type paume, appelé Paume1, sans donner d’indications sur sa direction (si elle est sans importance, pourquoi l’indiquer ?)
Paume2 = new Palm(up) : Je créé cette fois un objet de type paume, appelé Paume2, qui est positionné vers le haut. Je pourrais par exemple utiliser cet objet pour définir le palmspin.
Package m :
Class Side1(cap ou tip, longueur, épaisseur)
Class Side2(cap ou tip, longueur, épaisseur)
Class Body(longueur, épaisseur)
Method turn(angle, CW ou CCW, dimension)
Mon répertoire m contient donc un corps et deux extrémités. Les extrémités peuvent être créées en précisant ou non si elles sont de type « cap » ou « tip », et en donnant leur longueur et leur épaisseur.
De plus, j’associe au package m une méthode « turn » qui porte donc sur l’ensemble des classes contenues dans le package. Cette méthode prend en entrée un angle, un sens de rotation et une dimension (cad 1D, 2D ou 3D. Exemples : fingerroll = rotation en 1D ; palmspin = rotation en 2D ; charge = rotation en 3D).
Opérateurs :
Pour matérialiser les interactions entre les classes ou entre les objets, je distingue plusieurs types d’opérateurs :
Opérateurs physiques :
- || = « Collé à »
- / = « Sur »
- | = « en contact avec »
- X = « croisé avec »
-{ ; } = « suivi de »
Ces opérateurs portent sur des objets instanciés. Pour les définir précisément, il faudrait les présenter comme des fonctions qui à deux objets associent un objet ; qui plus est, il faudrait préciser l’ensemble de départ : les opérateurs ne peuvent pas nécessairement porter sur tous les objets (typiquement, Palm||BackHand n’a aucun sens…). Mais je laisse pour l’instant la description simplifiée. Ils transforment donc deux objets en un seul objet :
Finger1||Finger2 est l’objet constitué de l’index et du majeur collés.
NB : par soucis de simplification, je poserai désormais, pour i vallant 1, 2, 3, 4 ou T, Fingeri = i.
Opérateurs abstraits :
- V = « union »
- \ = « privé de »
- Wh = « whole ». C’est un raccourcis : h.Wh est la classe constitué de la réunion de toutes les classes du package h – c'est-à-dire la main entière.
Je définis l’opérateur unaire « ! » : il peut agir sur les opérateurs physiques ou abstraits, ou encore sur des méthodes. Exemple : !| signifie « jamais en contact avec » ; !turn signifie « reste immobile ».
Enfin, je définis les opérateurs de méthode : ce sont des opérateurs liés à une méthode donnée qui ne s’appliquent que lorsque la méthode est utilisée. Par exemple, l’utilisation de la méthode turn introduit l’opérateur « autour », noté « o », opérateur unaire prenant un objet quelconque en entrée.
Noter l’instanciation
Comme vous l’avez vu, rien ne distingue à première vue une classe d’un objet qui serait une instance de cette classe pour laquelle aucun attribut n’a été précisé. Par exemple, l’objet « Palm », sans indication sur sa direction, n’est pas visiblement différent de la classe « Palm ». Ce n’est absolument pas gênant pour un utilisateur, bien au contraire ; en revanche, informatiquement, la distinction est indispensable. Si un programme devait pouvoir lire les notations, il faudrait marquer cette différence. On le fait ainsi :
Lorsqu’une classe est instanciée, on la souligne.
Exemples :
1V3 est l’objet formé par l’index et l’annulaire. C’est donc l’objet que constitue l’ensemble de ces deux doigts, sans précisions sur leurs positions respectives : abstraitement, ils sont « réunis », c'est-à-dire « considérés ensembles », et cette réunion est ensuite instanciée.
1|3 est l’objet formé par l’index et l’annulaire en contact. Les deux objets sont d’abord instanciés, puis ils sont ensuite « fondus » en un nouvel objet, constitué de ces deux objets en contact. Leur liaison est désormais physique, et l’instanciation intervient nécessairement avant l’application de l’opérateur.
La notation a été définie par soucis de rigueur, mais je ne l’utiliserai pas par la suite, ce texte ayant vocation d’être lu par un humain et non par un ordinateur.
Enfin, un dernier petit paragraphe de définitions avant de passer à l’utilisation « en pratique » :
Objet statique ou objet dynamique
Lorsque j’instancie une classe, je créé un objet. Lorsque j’applique un opérateur entre deux classes et que je les instancie ensuite, je créé un objet. Lorsque je relie deux objets par un opérateur, je créé un nouvel objet. Mais que fais-je lorsque j’applique une méthode à un objet ?
C’est là qu’interviennent les notions d’objet statique et d’objet dynamique. Par définition, un objet dynamique est un objet auquel a été appliquée une méthode : c’est donc une succession continue d’objets statiques. Cependant, si la distinction existe, les deux sont des objets et seront utilisés comme des objets : les opérateurs physiques s’appliquent aussi bien sur les objets dynamiques que statiques.
Une précision important tout de même, avant de rendre tout cela plus clair par un exemple : Un objet dynamique est à l’origine un objet statique, auquel on a appliqué une méthode. Mais ceci ne donne aucune indications sur la position finale : un objet statique (une position de la main et du mods, généralement) est défini ; une méthode lui est appliquée (turn, le plus souvent), et l’objet devient un objet dynamique, mais rien n’indique la position finale : si l’on souhaite (ce n’est pas obligatoire !) la préciser, il faudra donner, après l’objet dynamique, l’objet statique correspondant à la nouvelle position.
Exemple et première utilisation concrète de la notation :
Je souhaite définir l’objet dynamique « ThumbAround ».
Je reviens rapidement sur un opérateur physique listé plus tôt : « { ; } ». Cet opérateur défini la séquence : il clôt l’énoncé d’un objet, et permet de donner l’objet suivant. On l’utilise ainsi :
{Objet1 ; Objet2 ; Objet3} est l’objet constitué de la séquence Objet1 puis Objet2 puis Objet3.
Je rappelle que la méthode turn introduit un opérateur « o » qui signifie « autour » et qui prend en entrée un objet quelconque (on note : o(objet) ). Il s’utilise uniquement après la méthode turn.
Nous allons donc créer l’objet ThumbAround_T2_T1. « ThumbAround_T2_T1 » sera son nom ; c’est une variable à laquelle on associe (via le symbole d’affectation « = ») un objet que je vais définir :
ThumbAround_T2_T1 = {
T/m.Wh.turn(2Pi, CCW, 2D)o(T)/1V2 ;
T/m.Wh/1 ; }
Notes : comme prévu, je n’ai pas souligné les objets instanciés. Mais il faudrait le faire pour être formel.
Le premier des deux objets est donc l’objet statique « Pouce sur le mod, lui-même sur les deux doigts 1 et 2 », au sein duquel le mod (m.Wh) s’est vu appliquer la méthode qui lui est associée (turn) : c’est donc un objet dynamique. On remarque que relier des objets statiques (T, 1V2) à un objet dynamique fait de l’ensemble de l’objet décrit un objet dynamique.
On a donc le premier objet suivant : Pouce sur le mod, lui-même sur les deux doigts, ensuite de quoi le mod tournera de 2Pi (tour complet), dans le sens contraire des aiguilles d’une montre, et la rotation sera plane.
Le deuxième objet est un objet statique qui décrit la position finale du mod (il arrive donc après le premier objet) : pouce sur le mod, lui-même sur 1.
La séquence de ces deux objets constitue le thumbaround. J’aurais pu être plus général en définissant le ThumbAround comme prenant en entrée des objets de type doigt, pour définir d’un coup les TA autours de n’importe quel doigt, mais s’aurait été encore moins lisible.
Quel est l’intérêt de tout cela ?
Eh bien, nous disposons maintenant de deux objets : ThumbAround_T2_T1, défini ci-dessus, et Twisted_Sonic, défini dans mon post précédent sur le topic de Skatox
Je vais donc créer un nouveau package, noté t pour tricks. Dedans, je mets simplement ces deux objets (qui sont en fait des classes, mais je ne fais plus la distinction).
J’ajouterai encore le symbole # pour importer le contenu d’un package donné.
Maintenant, prenons un cas concret :
Nous sommes en 2020. Le langage de programmation que j’ai défini porte désormais un nom, disons PSLanguage, et est interprétable par le logiciel PSReader, conçu par la richissime société Lindor&co.
Un nouveau spinneur, disons Georges, qui a bien sûr, comme tous les spinneurs, notre logiciel, contacte notre service d’aide : « bonjour, j’ai entendu parler d’un antique trick, le twisted acme revolution, mais je ne sais pas à quoi il correspond ! ».
Georges est débutant et n’a jamais appris à breakdowner quoi que ce soit. Qu’à cela ne tienne, notre service d’aide lui envoie le programme suivant :
“#t
Twisted_Acme_Revolution = {Twisted_Sonic ; ThumbAround}”
Bien sûr, Georges ne comprend rien au programme… mais il s’en fiche : il le copie/colle dans son beau logiciel PSReader. Ce dernier lit le programme :
#t : il importe le package t, qui contient des milliers de tricks (l’équipe de maintien le met constamment à jour avec tout ce qui se fait de nouveau). Parmi eux se trouvent les tricks Twisted_Sonic et ThumbAround.
Il créé ensuite l’objet Twisted_Acme_Revolution, ce dernier étant défini comme une séquence de deux objets que notre logiciel connaît déjà.
Enfin, Georges clique sur « Demonstration » : une vidéo s’affiche alors à l’écran, sur laquelle une main virtuelle exécute un twisted sonic, puis un thumbaround. L’enchaînement est saccadé, mais Georges n’aura aucune difficulté à reproduire les deux mouvements et comprendra très vite comment les relier en un seul enchaînement fluide. Il ajoute donc avec bonheur un nouvel enchaînement à son panel de tricks.
C’est présenté avec humour, mais l’idée est là : outre l’exercice intellectuel, définir un tel langage rend tout à fait possible la création d’un logiciel permettant de visualiser un trick ou un enchaînement donné à partir d’un code. N’importe qui serait libre d’ajouter de nouveaux objets aux différents package : en plus du package t, on pourrait créer un package c, qui contiendrait un très grand nombre de combos recensés et dument codés et qui serait mis à jour à chaque « grand » combo sorti. N’importe qui pourrait ensuite importer ce package c sur son logiciel PSReader et visualiser les combos qu’il souhaite.
Bref, les applications ne sont pas complètement vides de sens.
Extensions :
Ce que j’ai défini est simplement une base. De très nombreuses choses pourraient être rajoutées : un système plus adapté au XpXh, des objets de type wrist, arm & cie, de nouvelles méthodes (jump, etc)…
Et en effet, avec cette méthode, la notion de trick n’a plus de sens en soit. On peut définir n’importe quel enchaînement et le stocker dans un package donné. L’existences de doublons (plusieurs noms pour des tricks trop proches ou des enchaînements qui ne sont pas des tricks) ne pose aucun problème tant qu’ils sont chacun codés et stockés : le logiciel pourrait alors les lire de toute façon.
Le système que j’ai conçu ne remet en rien en cause le système classique de breakdownage, qui est adapté à une utilisation « manuelle », c'est-à-dire sans passer par un logiciel consacré. Mon système est complètement différent et ne s’utilise pas de la même façon.