Les membres ayant 30 points peuvent parler sur les canaux annonces, projets et hs du chat.
La shoutbox n'est pas chargée par défaut pour des raisons de performances. Cliquez pour charger.

Forum Casio - Vie communautaire


Index du Forum » Vie communautaire » TDM #XX : Les animations et les structures de données
Potter360 Hors ligne Rédacteur Points: 1255 Défis: 2 Message

TDM #XX : Les animations et les structures de données

Posté le 10/02/2021 18:25

Le Tutoriel du Mercredi (TDM) est une idée proposée par Ne0tux, qui recouvre tous les usages de la calculatrice - des applications de Casio à la conception de jeux en passant par la production artistique.

Aujourd'hui, nous allons voir les animations en C/gint et leur rapport avec les structures de données

Niveau : ★★★★☆
Tags : Animations, gint, POO

Bonjour et bienvenue dans ce TDM #21 !

Aujourd'hui nous allons parler des animations en C pour calculatrices et de comment les créer avec les structures !
Je précise que ce tutoriel contient des codes en C pour gint de Lephenixnoir, mais le code doit être facilement convertible pour le SDK "officiel" avec un poil de jugeote !

Voici le résultat final :



Durant ce tutoriel, j'utiliserai les frames suivants :


Frame idle



Frame de marche


Sommaire :

1) Qu'est ce qu'une animation ?
1.1) La boucle principale d'un jeu vidéo

2) Animation et boucle principale
2.1) Premières idées
2.2) L'utilité du sinon
2.3) L'apparition de la variable "frame suivant"

3) La POO (Programmation Orientée Objet)
3.1) Definition
3.2) L'exemple du catalogue d'animaux

4) S'inspirer de la POO pour les animations
4.1) Premières idées
4.2) Détection du clavier

5) Les structures de données en C
5.1) Equivalent des classes
5.2) Equivalent des objets
5.3) Affichage
5.4) Lire les entrées du joueur
5.5) Continuer l'animation précédente
5.6) Le code entier

6) Conclusion

7) Liens utiles


Commençons sans plus tarder par des révisions :

Qu'est ce qu'une animation ?

La question paraît bête : oui, je sais ce qu'est une animation : c'est une suite d'images passées très vite qui donne une impression de mouvement !

Oui, effectivement, bravo !
Mais dans un jeu vidéo ?

La boucle principale d'un jeu vidéo

Vous savez peut être qu'un jeu vidéo est, en général, constitué d'une boucle principale. Par exemple, pour détecter si l'utilisateur appuie sur la touche [EXE], il va y avoir une boucle principale, dans laquelle le jeu détecte si l'utilisateur appuie sur la touche. En algorithmique ça donne ca :

Répéter ∞ fois {
     Si touche [EXE] est pressée : {
          //faire l'action
     }
}

et, en C/gint on a approximativement ca :

int main void(){
    while(True){
        if(getkey().key == KEY_EXE){
             //faire l'action    
        }
    }
}


Mais...attendez...une boucle qui change selon l'environnement et qui va très vite...ça ne vous rappelle pas quelque chose ?

Oui, les animations !

Animations et boucle principale

Premières idées

Prenons par exemple une "boucle" d'animation (une animation qui se répète toutes les 3 images par exemple).
On pourrait organiser un truc comme ça : on crée une boucle, et les images s'affichent chacune une répétition de la boucle sur 3.
On pourrait alors imaginer un truc du genre :

A la première répétition : afficher image1
A la deuxième répétition : afficher image2
A la troisième répétition : afficher image3

Puis on recommence au début !

C'est un bon moyen de faire une animation, mais comment la réaliser ?
Avec une variable, du genre :

Nouvelle variable nommée "a" = 1

Répéter ∞ fois : {
     si a = 1 alors afficher la première image
     si a = 2 alors afficher la deuxième image
     si a = 3 alors afficher la troisième image

     si a = 1 alors mettre la variable "a" à 2
    sinon si a = 2 alors mettre la variable "a" à 3
    sinon si a = 3 alors mettre la variable "a" à 1


}

?

En soi cela marche mais ce code est long et n'est pas très lisible, il faut de la concentration pour le comprendre.


Et puis, imaginez que vous vous retrouvez avec une animation contenant 3 images (que je vais appeler dorénavant des "frames"), le code serait complexe et illisible : on appelle cela un code spaghetti

Voici la représentation mathématique d'un code spaghetti :


C'est pas beau à voir, hein ?.
Le second problème, c'est que tous les "si ... alors ... sinon ..." sont placés dans le sinon du premier "si ... alors ... sinon ...", ce qui pose des problèmes : si le premier "si ... alors ... sinon ..." a un problème faisant que le "sinon" ne sera jamais exécuté, tout le reste est à l'arrêt.

On appelle cela les dépendances : certaines lignes de code sont dépendantes d'autres lignes, et cela peut poser problème, et peut créer l'effet domino : en effet, imaginons que dans un code toutes les lignes sont dépendantes (ce qui est très peu probable), un problème qui ne concerne que la ligne 1 va arrêter la ligne 2 car elle est dépendante de la ligne 1, la ligne 2 va arrêter la ligne 3, la 3 va arrêter la 4 etc...

Mais alors, pourquoi mettre tout le code dans des "sinon" ?

Très bonne question.

L'utilité du "sinon"

Pour y répondre je vais prendre un exemple de code en algorithmique que j'appelle " l'interrupteur " : un texte est affiché à l'écran, "1" ou "0", et quand l'utilisateur appuie sur une touche, disons [EXE], l'état du texte change : si "0" était affiché on affiche maintenant "1" et vice-versa.
Cela donne :

Répéter ∞ fois : {
     Afficher la variable "a"
     Si la touche EXE est pressée alors :
          Si la variable "a" = 0 alors mettre la variable "a" à 1
          Sinon mettre la variable "a" à 0
}

Le sinon est indispensable : réfléchissons. Imaginons que l'on ne le mette pas, on a ça :

Répéter ∞ fois : {
     Afficher la variable "a"
     Si la touche EXE est pressée alors :
          Si la variable "a" = 0 alors mettre la variable "a" à 1
          Si la variable "a" = 1 alors mettre la variable "a" à 0
}

La suite imagine que a = 0 au départ : lorsque EXE est pressé on a cette ligne : Si la variable "a" = 0 alors mettre la variable "a" à 1
Or a = 0 donc ce if s'exécute et a = 1.
Ensuite : Si la variable "a" = 1 alors mettre la variable "a" à 0
Depuis la ligne précédente a = 1 donc ce if s'exécute donc a = 0.
Au final, a n'a pas changé, le code ne marche pas.
Le sinon ne vérifie pas la condition avant de s'exécuter mais avant d'exécuter le if, donc ici cela marche.

Attends... j'ai une idée... pourquoi ne pas créer une variable framesuivant pour chaque image ? Et dans le code on dit : affiche le frame actuel et met le frame actuel au frame suivant !

Effectivement, c'est la solution, mais... comment faire ?

L'apparition de la variable "frame suivant"

Les variables sont multipliées par 2 ; pour 3 frames on a ces variables : frame1 ; frame1next ; frame2 ; frame2next ; frame3 ; frame3next.
Et cela en fait 6 !
Encore là, c'est acceptable, mais imaginez une animation de 60 frames : on a 120 variables !
Et si en plus chaque frame a une position x et une position y, ce qui est plus propre, chaque frame a 4 variables ; pour le frame 1 ces variable sont : frame1 (l'image) , frame1next, frame1posx , frame1posy.
Pour une animation de 60 frames, cela représente tout de même 240 variables !
Cela impacte en premier lieu le développeur, qui ne s'y retrouvera pas dans ses variables, mais aussi la machine, car les variables prennent de la RAM, et l'utilisateur, qui va voir le programme ralenti.

Ha, j'ai une idée ! Et si on... heu... ha non...heu...


Bon, j'ai la solution, ne cherchez pas.
Et si on s'inspirait de...

La POO (Programmation Orientée Objet)

On m'informe dans l'oreillette que j'ai dit un mot compliqué...
Ne vous inquiétez pas, je vais expliquer.
Je demande juste aux programmateurs pointilleux de ne pas me cracher dessus : je vais résumer un max.

Résumons... nous aurions besoin de plusieurs variables par frames...

Définition

La programmation orientée objet est un style d'écriture du code, et Wikipédia dit ici que :
Dans ce style, le code source est une suite de descriptions de classes ou de prototypes, avec la description de leurs caractéristiques ( propriétés ) et de leurs comportements ( méthodes ).


Ne paniquez pas.
En POO, on crée des objets, et les variables ont des "états" en fonction de ces objets.

L'exemple du catalogue d'animaux

Prenons un exemple : je veux faire un programme simple dans un langage quelconque qui demande à l'utilisateur le nom de l'animal et la caractéristique, et le programme donne le résultat (Exemple : le programme demande le nom de l'animal, l'utilisateur répond "Chien", il demande la caractéristique, l'utilisateur rentre "Cri" et le programme renvoie "Wouf !").
Pour cela on pourrait faire un truc du genre : (en algorithmique)

Afficher : "Quel animal ?"
Attendre la saisie de l'utilisateur et la stocker dans la variable "animal"
Afficher : "Quelle caractéristique ?"
Attendre la saisie de l'utilisateur et la stocker dans la variable "caractéristique"
Si animal = "chien" : {
     Si caractéristique = "Cri" : {
          Afficher "Wouf !"
     }
     Si caractéristique = "Poids" : {
          Afficher "Le poids moyen se situe entre 15 et 25 kg."
     }
Si animal = chat : {
     Si caractéristique = "Cri" : {
          Afficher "Miaou !"
     }
     Si caractéristique = "Poids" : {
          Afficher "Le poids moyen se situe entre 4 et 6 kg."
     }
}

Vous le voyez, ce code est long et il faut du temps pour le comprendre.
L'inventeur de la POO a trouvé ce problème embarrassant, et voici sa solution : on crée deux variables : Cri et Poids.
On crée deux "objets" : chat et chien, et pour chaque objet une "version" différente de la variable est crée : par exemple il existe deux versions de la variable Cri : celle du chat et celle du chien.

Voici une partie du code amélioré avec la POO :

Nouvelle variable "Cri"
Nouvelle variable "Poids"
Nouvel objet "Chien" : {
    Sa version de "Cri" = "Wouf !"
    Sa version de "Poids" = 20
}
Nouvel objet "Chat" : {
    Sa version de "Cri" = "Miaou !"
    Sa version de "Poids" = 4
}

Oui, c'est perturbant mais vous allez vous y faire.
Tous mes objets sont des animaux, mais imaginons que je veuille créer un objet "fourmi", pour laquelle je veux enlever la variable "cri".

Facile : on ajoute au code précédent :
Nouvel objet "Fourmi" : {
    Sa version de "Poids" = "150 milligrammes"
}
!


En soi oui. Mais la programmation est pleine de règles, et on ne peut pas choisir de mettre ou non une variable. C'est un peu comme pour un livre : si tu écris un roman mais que tu ne trouves pas de nom, tu ne peux pas décider de ne pas en mettre.

Il va falloir créer des "types" d'objets. On va par exemple créer le type "Animal", dans lequel on va créer les variables "Poids" et "Cri", et créer le type "Insecte" dans lequel on va créer la variable "poids" ; en programmation on appelle ces types des "classes".
On peut alors obtenir un truc du genre :

Nouvelle classe "Animal" : {
    Elle contient la nouvelle variable "Cri"
    Elle contient la nouvelle variable "Poids"
}
Nouvelle classe "Insecte" : {
    Elle contient la nouvelle variable "Poids"
}
Nouvel objet "Chien" de type "Animal" : {
    Sa version de "Cri" = "Wouf !"
    Sa version de "Poids" = 20
}
Nouvel objet "Chat" de type "Animal" : {
    Sa version de "Cri" = "Miaou !"
    Sa version de "Poids" = 4
}
Nouvel objet "Fourmi" de type Insecte : {
    Sa version de "Poids" = "150 milligrammes"
}

On touche au but ! Mais, pour les entrées de l'utilisateur ?
En POO, on peut récupérer la "version" d'une variable via cette syntaxe : (la plus courante)
[Nom_de_l'objet].[nom_de_la_variable]
Par exemple, dans notre cas, écrire dans mon programme Afficher Fourmi.Poids affichera "150 milligrammes", ou écrire Afficher Chien.Cri affichera "Wouf !".
On pourrait donc faire ca :

Afficher : "Quel animal ?"
Attendre la saisie de l'utilisateur et la stocker dans la variable "animal"
Afficher : "Quelle caractéristique ?"
Attendre la saisie de l'utilisateur et la stocker dans la variable "caractéristique"
Nouvelle classe "Animal" : {
    Elle contient la nouvelle variable "Cri"
    Elle contient la nouvelle variable "Poids"
}
Nouvelle classe "Insecte" : {
    Elle contient la nouvelle variable "Poids"
}
Nouvel objet "Chien" de type "Animal" : {
    Sa version de "Cri" = "Wouf !"
    Sa version de "Poids" = 20
}
Nouvel objet "Chat" de type "Animal" : {
    Sa version de "Cri" = "Miaou !"
    Sa version de "Poids" = 4
}
Nouvel objet "Fourmi" de type Insecte : {
    Sa version de "Poids" = "150 milligrammes"
}
Afficher Animal.Caractéristique

Et on arrive au résultat souhaité !

Mais les animations dans tout ca ?
Ca arrive...

S'inspirer de la POO pour les animations

Premières idées

On pourrait par exemple faire un truc comme cela pour relier les 2 sujets...

Nouvelle classe "frames" : {
    Nouvelle variable "Image"
    Nouvelle variable "Nextframe"
    Nouvelle variable "Posx"
    Nouvelle variable "Posy"
}
Nouvel objet "Frame1" de type "frames" : {
    image = image_frame1
    nextframe = "Frame2"
    Posx = 1
    Posy = 10
}
Nouvel objet "Frame2" de type "frames" : {
    image = image_frame2
    nextframe = "Frame3"
    Posx = 1
    Posy = 10
}
Nouvel objet "Frame3" de type "frames" : {
    image = image_frame3
    nextframe = "Frame1"
    Posx = 1
    Posy = 10
}
Nouvelle variable "FrameActuel" = Frame1
Répéter ∞ fois : {
   Afficher FrameActuel.image
   Attendre 25 ms
   FrameActuel = FrameActuel.nextframe
}

On commence à y arriver !
Ici, on a une animation qui fonctionne, mais qui ne s'arrête pas.

Détection du clavier

Il faudrait créer une variable de type boolean isAnimated, la mettre à true si on appuie sur le bouton permettant d'avancer, et l'animation se fait seulement si isAnimated est à true.
Et pour savoir quand l'animation est finie, on crée une variable AnimateTime, sorte de décompte avant la fin du frame.
On a ce code :

Nouvelle classe "frames" : {
    Nouvelle variable "Image"
    Nouvelle variable "Nextframe"
    Nouvelle variable "Posx"
    Nouvelle variable "Posy"
}
Nouvel objet "Frame1" de type "frames" : {
    image = image_frame1
    nextframe = "Frame2"
    Posx = 1
    Posy = 10
}
Nouvel objet "Frame2" de type "frames" : {
    image = image_frame2
    nextframe = "Frame3"
    Posx = 1
    Posy = 10
}
Nouvel objet "Frame3" de type "frames" : {
    image = image_frame3
    nextframe = "Frame1"
    Posx = 1
    Posy = 10
}
Nouvelle variable "FrameActuel" = Frame1
Répéter ∞ fois : {
   Si touche avancer est pressée : {
        Mettre isAnimated à true
        Mettre AnimateTime à 3
        //3 car il y a 3 frames avant la fin de l'animation
   }
   Si isAnimated = true : {
        Afficher FrameActuel.image
        Attendre 25 ms
        FrameActuel = FrameActuel.nextframe
        Enlever 1 à AnimateTime
        Si AnimateTime = 0 : {
             //l'animation est terminée
             Mettre isAnimated à false
        }
   }
   Sinon : {
        //Idle est l'image de la position inactive
        Afficher Idle
   }
}

Bon, on a la base, maintenant...

Les structures de données en C

Bon, super, nous avons le code en algorithmique !
Mais je vous rappelle que gint, lui, est en C !
Alors comment passer de l'un à l'autre ?

Equivalent des classes

En C, la POO n'existe pas , mais il existe une solution similaire : les "structures".
Pour définir l'équivalent d'une classe, rien de plus simple :

struct name_of_class {
int variable1;
long variable2;

}


Equivalent des objets

Pour définir l'équivalent d'un objet, c'est plus compliqué. Je vais d'abord donner la syntaxe d'un objet faisant partie de la classe "name_of_class" crée précédemment :

struct  name_of_class name_of_object[2] {
{12,14}
//Dans l'exemple précédent, la valeur de la variable variable1 pour l'objet name_of_object[1] est 12 et la valeur de la variable variable2 pour l'objet name_of_object[1] est 14  
{20,41}
}

Alors, je sais que c'est difficile à comprendre, mais chaque "objet" créé est une liste d'"objets".
Mais en soi cela peut être une bonne idée : on crée une "liste d'objets" pour chaque animations, et chaque objet est un frame.
Concrètement, voyons le code de la structure anim, je vous le donne et vous explique après :
struct anim {
     bopti_image_t *img;
     int duration;
     struct anim *next;
};

La 1ère variable, bopti_image_t *img; est la variable contenant l'image.
La 2ème, duration, contient le nombre de frames sur lesquels l'image va rester avant de passer à une autre animation
La 3ème, struct anim *next;, est un pointeur.
C'est une variable qui envoie vers une autre variable. Ici, elle contient le frame suivant, qui est aussi de type struct.
Voici donc ce qu'on obtient pour l'animation de marche :

struct anim anim_walk[2] = {
    { &img_personnagemarche, 3 , &anim_walk[1] },
    { &img_personnage, 3, &anim_walk[0] },
};

Pour la facilité du code on va ajouter une animation idle :

struct anim anim_idle[1] = {
    { &img_personnage, 1, &anim_idle[0] },
};

Et voici finalement tout le code des structures, à mettre avant int main(void) :

struct anim {
     bopti_image_t *img;
     int duration;
     struct anim *next;
};

struct anim anim_idle[2] = {
    { &img_personnage, 40, &anim_idle[1] },
    { &img_personnage2, 40, &anim_idle[0] },
};
struct anim anim_walk[2] = {
    { &img_personnagemarche, 3 , &anim_walk[1] },
    { &img_personnage, 3, &anim_walk[0] },
};


Pour créer la variable current_anim, sachant que celle ci est un pointeur, il faut faire :

struct anim *current_anim = &anim_idle[0];

&anim_idle[0] est l'animation par défaut, sachant qu'en arrivant sur l'add-in le personnage est normalement en position idle.

Et voici toutes les variables à définir avant la boucle :

    struct anim *current_anim = &anim_idle[0];
    int current_anim_time_left = 0;
    extern bopti_image_t img_personnage;
    extern bopti_image_t img_personnagemarche;
    //État du personnage : 0=arrêté, 1=marche
    int state = 0;
    //État du personnage au frame précédent
    int previous_state = 0;
    


Affichage
Pour l'affichage de notre animation, rien de compliqué : on affiche aux positions x et y de current_anim l'image de current_anim comme ceci :

dclear(C_WHITE);
dimage(current_player->x,current_player->y, current_anim->img);
dupdate();


Lire les entrées du joueur
Ensuite on va lire les entrées du joueur ; et pour cela nous allons utiliser keydown qui nécessite un clearevents(); qui va effacer les évènements précédents.
Lors de l'appui sur une touche il va falloir changer d'animation : pour faire cela proprement, on va créer 2 variables : state, qui va contenir l'état de notre personnage (si la touche permettant d'avancer est pressée, state = 1) et previous_state, qui contient le state du frame précédent.
Si state = 1 mais que previous_state = 0, on vient de commencer à marcher, et on peut donc passer à l'animation de marche, et vice-versa.
Ca donne : (entrées + test des variables state et previous_state)

clearevents();
state = 0;
if(keydown(KEY_RIGHT))
      state = 1;
if(previous_state == 0 && state == 1)
{
      //On vient de commencer à marcher
      current_anim = &anim_walk[0];
      current_anim_time_left = current_anim->duration;
}
else if(previous_state == 1 && state == 0)
{
      // On vient de s'arrêter
      current_anim = &anim_idle[0];
      current_anim_time_left = current_anim->duration;
}


Continuer l'animation précédente
Bon, ca c'est si on vient de commencer à marcher, ou de s'arrêter, mais si il n'y a aucun changement ?
Et bien, on enlève 1 à current_anim_time_left et, si il est égal à 0, on met current_frame au frame suivant
et current_current_anim_time_left à current_anim_time_left = current_anim->duration !
Voici le code : (à placer après le bout de code précédent, le else correspond à " if(previous_state == 0 && state == 1) ")

        else
        {
            //On continue l'anim précédente
            current_anim_time_left--;
            if(current_anim_time_left <= 0)
            {
                current_anim = current_anim->next;
                current_anim_time_left = current_anim->duration;
            }
        }

Puis, si state = 1, on ajoute 1 à x pour que le personnage avance comme ceci :

if(state == 1)
        {
                x = x+1;
     }
        
        }

Enfin, on met le délai d'attente, puis on met previous_state à state :

        //Délai
        sleep_us(25000);

        // Préparation des invariants du frame suivant
        previous_state = state;

Et voilà !

Le code entier

Voici le code entier :

#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/clock.h>
extern bopti_image_t img_personnage;
extern bopti_image_t img_personnagemarche;

struct anim {
     bopti_image_t *img;
     int duration;
     struct anim *next;
};

struct anim anim_idle[2] = {
    { &img_personnage, 40, &anim_idle[1] },
    { &img_personnage2, 40, &anim_idle[0] },
};
struct anim anim_walk[2] = {
    { &img_personnagemarche, 3 , &anim_walk[1] },
    { &img_personnage, 3, &anim_walk[0] },
};
int main(void)
{
    struct anim *current_anim = &anim_idle[0];
    int current_anim_time_left = 0;
    extern bopti_image_t img_personnage;
    extern bopti_image_t img_personnagemarche;


    //État du personnage : 0=arrêté, 1=marche
    int state = 0;
    // État du personnage au frame précédent
    int previous_state = 0;

    while(a != 1)
    {
        //Affichage
        dclear(C_WHITE);
        dimage(current_player->x,current_player->y, current_anim->img);

        dupdate();
        //Lecture des entrées ; si on n'appuie sur rien, state=0
        clearevents();
        state = 0;


        if(keydown(KEY_RIGHT))
            state = 1;

        //Exécution des animations

        if((previous_state == 0 && state == 1))
        {
            //On vient de commencer à marcher
            current_anim = &anim_walk[0];
            current_anim_time_left = current_anim->duration;
        }
        else if(previous_state == 1 && state == 0)
        {
            //On vient de s'arrêter
            current_anim = &anim_idle[0];
            current_anim_time_left = current_anim->duration;
        }
        else
        {
            //On continue l'anim précédente
            current_anim_time_left--;
            if(current_anim_time_left <= 0)
            {
                current_anim = current_anim->next;
                current_anim_time_left = current_anim->duration;
            }
        }

        //Simulation du monde
              
        if(state == 1)
        {

          xref = xref-1;
        
        
        }    

        //Délai
        sleep_us(25000);

        //Préparation des invariants du frame suivant
        previous_state = state;
    }

    getkey();
    return 1;
}

On a à présent une belle animation, celle ci normalement :



Conclusion

Vous avez appris dans ce tutoriel les bases des animations, la POO et son équivalent en C, les structures de donnés et comment utiliser ces dernières en C/gint !

J'espère que ce TDM vous aura aidé dans la réalisation de vos animations, j'ai été très content de le faire !

Merci à Lephenixnoir et à Dark storm pour leur aide qui m'a été précieuse !

Si vous avez des questions, lâchez vous en commentaires !
Liens utiles

Voir le TDM précédent : Comprendre et utiliser le path sous Linux

Consulter l'ensemble des TDM


FlamingKite Hors ligne Membre Points: 516 Défis: 9 Message

Citer : Posté le 10/02/2021 18:40 | #


Eh ben...
Je ne m'attendais pas à ça on peut dire.

Sur le contenu même, je ne pourrai pas juger, non pas que je ne sois pas compétent là dedans mais si en fait c'est ça .

Par contre sur la forme, là je peux juger, et je suis très agréablement surpris ! C'est plutôt structuré et bien écrit, et puis il y a vraiment une amélioration depuis ton Press Shift par exemple.
Je t'encourage donc à continuer dans cette voie (dans la mesure où tu dis pas n'importe quoi hein) et puis tu pourras te faire exploiter comme rédacteur par les admins
Dark storm Hors ligne Labélisateur Points: 11641 Défis: 176 Message

Citer : Posté le 10/02/2021 18:53 | #


Merci pour l'initiative, c'est toujours chouette d'avoir du contenu inédit sur le site

Par contre… Tu mélange beaucoup de choses, y'a aussi pas mal d'inexactitudes voir d'erreurs.

Pourquoi mélanger POO et animation ? Les deux sont complètement différents, et le premier nécessiterait beaucoup plus qu'un TDM pour être abordé.
Le C n'est pas fait pour faire de la POO. Tu peux tricker avec des pointeurs de fonctions dans des structures, mais c'est vite assez lourd, compliqué et par conséquent crade. D'ailleurs utiliser des structures comme tu fais, même si c'est la première étape, n'est pas considéré comme de la POO.
Pour ce qui est des animations avec gint, Lephe a déjà couvert ça dans les tutos gint : https://www.planet-casio.com/Fr/forums/topic14914-1-tutoriels-dutilisation-de-gint.html#177758

Pour faire plus général, c'est très fouilli. Je te conseille de poser le plan de ton tutoriel, le détailler en section, sous section, etc. jusqu'à ce que la structure soit claire et cohérente. Ensuite tu pourra remplir les parties. Commencer par le plan permet d'organiser sa pensée, et par conséquent rendre clair ton exposé.

Au passage, j'ai retiré le numéro du TDM, on t'en attribuera un quand ton article sera prêt à être publié en page d'accueil
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Lephenixnoir Hors ligne Administrateur Points: 24678 Défis: 170 Message

Citer : Posté le 10/02/2021 21:02 | #


Oh, intéressant ! Et c'est un article détaillé, super ! À publier, c'est sûr.

Attention quand même, si tu veux publier quelque chose il faut au moins prévenir un rédacteur... même entre nous on ne publie pas d'articles à l'improviste.

Dans l'ensemble c'est un peu confus, mais rien n'est parfait du premier coup et je trouve ça largement suffisant sur le contenu. Je n'ai que deux remarques à faire.

D'une part ce que tu décris ce n'est pas vraiment de la POO, qui comme tu le sais n'existe pas en C ; tu ne parles que de structures. Je suggère de reformuler en disant « structures » à la place de « POO », sachant que la grande idée y est toujours : on groupe dans une structure des données qui vont ensemble (on n'a juste pas le code avec).

Et sinon l'espacement est très irrégulier dans ton texte, avec des indentations qui manquent (ça tu peux pas le laisser passer !) et beaucoup d'espacements différents autour des blocs de code ; en principe tu dois avoir une ligne blanche avant le [code], et pas de ligne blanche après le [/code] (il y a en une automatiquement), ce qui donne ça.

code

Une passe rapide de 5-10 minutes pour ajuster ces espacements et lndentations donnerait un aspect plus professionnel à ton tuto.

Sinon je suis chaud pour le publier. Contrairement à Darks, je ne pense qu'il y ait de mérite à tout refaire en profondeur. Le code est effectivement inspiré (en partie pris) des tutos d'utilisation de gint, donc évidemment ça recoupe. Et ce serait rude de refuser des efforts de rédaction.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Potter360 Hors ligne Rédacteur Points: 1255 Défis: 2 Message

Citer : Posté le 11/02/2021 19:02 | #


Merci beaucoup pour vos retours !

@Lephenixnoir, je ne savais pas qu'il fallait demander à un rédacteur, j'y ferai attention à l'avenir ! Et cela serait encore mieux si je deviens rédacteur hum hum...

J'ai fait les changements que tu m'a indiqué, merci.
J'ai par contre laissé "POO" lorsque je ne parlais pas du C, car je pense que c'est un bon moyen d'amener l'utilisateur aux structureqs.
J'ai rajouté des sous titres dans les sous titres ( ), et je vous ai mentionné à la fin, toi et Dark storm.

Merci beaucoup pour tes conseils, l'article est il prêt à être publié ? (je sais que la vie n'est pas si simple)
Globalement, coder. Mal, mais coder.
Lephenixnoir Hors ligne Administrateur Points: 24678 Défis: 170 Message

Citer : Posté le 11/02/2021 19:08 | #


Yay ! C'est bien ce à quoi je pensais, la distinction structure/POO est vraiment mieux. Encore que les indentations sont toujours un peu, euh... exotiques par endroits. Regarde bien au début, notamment dans l'exemple du catalogue d'animaux qui n'est pas du tout indenté.

Une photo/vidéo du résultat serait pas mal pour aller à la fin de l'article (si tu y arrives).

Sinon j'ai bien prévenu que même entre nous on s'avertit avant de publier hé hé. :3
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Tituya Hors ligne Administrateur Points: 2156 Défis: 26 Message

Citer : Posté le 11/02/2021 19:16 | #


Je précise que c'est à des fins d'organisation qu'on essaye d'avertir les autres quand on poste un article

Ça évite des moments un peu de panique comme lors de la publication de mon dernier Press Shift

L'article en lui même est largement mieux construit que le précédent, tu fais des progrès !
Le truc qui manque selon moi, c'est les photos. Avoir une illustration des étapes est assez importante pour tenir le lecteur jusqu'à la fin de l'article.

Actuellement, on sait qu'on arrive à une animation, mais concrètement, ça peut donner quoi visuellement sur un programme ? C'est une question que risque de se poser le lecteur

Sinon merci, c'est quand même du bon boulot
Bretagne > Reste du globe
(Et de toute façon, vous pouvez pas dire le contraire)
Projet en cours : Adoranda

Mes programmes
Hésite pas à faire un test !


Dark storm Hors ligne Labélisateur Points: 11641 Défis: 176 Message

Citer : Posté le 11/02/2021 19:28 | #


Beaucoup mieux

J'ai pas testé, mais y'a des incohérences entre les snippets et le code complet, en particulier ce passage : if((previous_state == 0 && state == 1) || (previous_state == -1 && state == 1)) . Tu n'explique pas d'où sort le previous_state == -1, ce qui peut surprendre.

Revoir un poil l'indentation. Que ce soit du C ou du pseudo-code, tiens toi à un style et respecte-le. La page Wikipédia à ce sujet est assez bien faite, tu peux piocher ce qui t'intéresse.

+1 pour les illustrations, c'est toujours mieux avec. On peut t'aider à les héberger sur le site si tu le souhaite.

Pour les commentaires inline, je conseille la syntaxe // Comment par rapport à /* Comment */, d'une part car c'est par convention utilisé comme tel, et d'autre part car si ma mémoire ne me trompe pas, les commentaires inline // sont affichés en vert part le site.

Il ne reste plus grand chose à modifier avant que ce soit un bon article
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Potter360 Hors ligne Rédacteur Points: 1255 Défis: 2 Message

Citer : Posté le 12/02/2021 07:01 | #


Ah, pour le state = -1 j'ai copié une partie du code d'Elphorina qui contient state = -1 pour reculer, et j'ai oublié de l'enlever !
Modifié !
Je vais indenter, et voir comment mettre des illustrations !

Ajouté le 13/02/2021 à 11:52 :
J'ai rajouté des illustrations et j'ai indenté !

Ajouté le 14/02/2021 à 15:34 :
J'ai rajouté un sommaire fonctionnant avec des ancres ! (et j'en ai bavé )
Globalement, coder. Mal, mais coder.
Lephenixnoir Hors ligne Administrateur Points: 24678 Défis: 170 Message

Citer : Posté le 14/02/2021 15:37 | #


Bien joué ! o/
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Potter360 Hors ligne Rédacteur Points: 1255 Défis: 2 Message

Citer : Posté le 14/02/2021 15:38 | #


Merci !
Globalement, coder. Mal, mais coder.

LienAjouter une imageAjouter une vidéoAjouter un lien vers un profilAjouter du codeCiterAjouter un spoiler(texte affichable/masquable par un clic)Ajouter une barre de progressionItaliqueGrasSoulignéAfficher du texte barréCentréJustifiéPlus petitPlus grandPlus de smileys !
Cliquez pour épingler Cliquez pour détacher Cliquez pour fermer
Alignement de l'image: Redimensionnement de l'image (en pixel):
Afficher la liste des membres
:bow: :cool: :good: :love: ^^
:omg: :fusil: :aie: :argh: :mdr:
:boulet2: :thx: :champ: :whistle: :bounce:
valider
 :)  ;)  :D  :p
 :lol:  8)  :(  :@
 0_0  :oops:  :grr:  :E
 :O  :sry:  :mmm:  :waza:
 :'(  :here:  ^^  >:)

Σ π θ ± α β γ δ Δ σ λ
Veuillez donner la réponse en chiffre
Vous devez activer le Javascript dans votre navigateur pour pouvoir valider ce formulaire.

Si vous n'avez pas volontairement désactivé cette fonctionnalité de votre navigateur, il s'agit probablement d'un bug : contactez l'équipe de Planète Casio.

Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2024 | Il y a 74 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd