Forums Développement Multimédia

Aller au contenu

Petit chatbot sur 2 frames : frame 2 qui bug

CODE

4 réponses à ce sujet

#1 vegetalain

    Ceinture Orange

  • Members
  • PipPipPip
  • 34 messages

Posté 26 November 2015 - 09:11 AM

Bonjour, alors voilà je suis en train d'essayer de faire un petit chatbot :D. Avec divers bouts d'AS3 et quelques conseils avisés j'espère faire un truc qui fonctionne bien.

Il y a des mots clés avec une réponse (parfois aléatoire), un son, un effet typewriter pour la réponse.
Je compte répartir mon bot sur plusieurs frames en fait :

1. La frame 1 sert à la conversation de base, avec :
- des phrases par défaut si aucun mot clé n'est détecté.
- des mots clés et une phrase de réponse correspondante.

2. La frame 2 sert à une deuxième conversation avec :
- des phrases par défaut si aucun mot clé n'est détecté.
- des mots clés et une phrase de réponse correspondante.

Donc, quasiment "la même chose" au niveau du traitement du texte... seuelement y'a un problème :

La frame 1 fonctionne nickel, mais arrivé à la frame 2 il me sort toujours les phrases par défaut, où que je mette la détection du mot clé "machin", il est ignoré par l'as3 et je sais pas pourquoi. J'ai pourtant changé les noms des variables, etc, mais si c'était ça, même les phrases par défaut devraient être ignorées (je pense) ; or ce n'est pas le cas.

- Pour valider ce que vous dîtes, pas de bouton, juste appuyer sur "Entrée".
- Pour passer de la frame 1 à la frame 2 il faut taper "mode"
- le mot test pour la frame 1 est "coucou"
- le mot test pour la frame 2 est "machin"
- tapez n'importe quoi pour avoir les phrases "d'incompréhension"

Voici le contenu avec donc :
- un champ input "a1" pour l'utilisateur
- un champ dynamique "c1" où la réponse est stockée
- un champ dynamique "d1" où elle est affiché avec l'effet typewriter

Premier calque, Frame 1 et 2 ensemble :

var mysound = new zs0();         
mysound.play();  
var myString:String;
var myArray:Array;  

//-----------------------------------------------------------------    
addEventListener(Event.ADDED_TO_STAGE, hophophop);     
function hophophop(event:Event):void { 
        if (myArray.length > 0) {
                d1.appendText(myArray.shift());
        } else {       
                removeEventListener(Event.ADDED_TO_STAGE, hophophop);  
                SoundMixer.stopAll();
        }      
}
//-----------------------------------------------------------------     Délais de réponse en cours
        var zedelais:Array = ["2000", "4000", "6000"];
        var delaisok:Number = zedelais[Math.floor(Math.random()*zedelais.length)];  
        var zeTimer:Timer = new Timer(delaisok,1);
       
        zeTimer.addEventListener(TimerEvent.TIMER, cestparti);
        function cestparti(event:TimerEvent):void{
                 d1.text = "";
                        myString = c1.text;    
                        myArray = myString.split("");// seperates each letter
                        addEventListener(Event.ENTER_FRAME, hophophop);
                        mysound.play();
        }
 



Second calque, Frame 1 :

//                        BLABLA INITIAL DE BASE
SoundMixer.stopAll();
//----------------------------------------------------------------
a1.addEventListener(KeyboardEvent.KEY_DOWN, clavier_01);
function clavier_01(event:KeyboardEvent):void {
    if (event.keyCode == Keyboard.ENTER) {
        gogogo_01();    
    }
}
 
function gogogo_01():void {
var aok: String = a1.text;
//-----------------------------------------------------------------    RIEN DANS LA BASE  
    var okunide01:Array = ["De quoi?", "Je ne comprends pas.", "pardon??"];
    var saispas01:String = okunide01[Math.floor(Math.random()*okunide01.length)];  
    c1.text = saispas01;
 
//-----------------------------------------------------------------    Conversation standard
    if(aok.indexOf("coucou") != -1){c1.text = "Salut?";}
 
//-----------------------------------------------------------------    Conversation standard
    if(aok ==("mode")){c1.text = "mode ok";gotoAndStop(2);}
 
    a1.text = "";
    d1.text = "";
   
//-----------------------------------------------------------------    Délais de la réponse
    zeTimer.delay = zedelais[Math.floor(Math.random()*zedelais.length)];
    zeTimer.start();
 
}



Second calque, Frame 2 :


//                        BASE AVEC LES INFOS
SoundMixer.stopAll();
//----------------------------------------------------------------
a1.addEventListener(KeyboardEvent.KEY_DOWN, clavier_02);
function clavier_02(event:KeyboardEvent):void {
    if (event.keyCode == Keyboard.ENTER) {
        gogogo_02();    
    }
}
 
function gogogo_02():void {
var inxjgf: String = a1.text;    
//-----------------------------------------------------------------    RIEN DANS LA BASE  
    var aze:Array = ["Erreur truc.","Je n'ai rien à ce sujet.","Aucune info disponible."];
    var rtg:String = aze[Math.floor(Math.random()*aze.length)];  
    c1.text = rtg;
 
//-----------------------------------------------------------------    REFERENCE TROUVÉE
    if(inxjgf.indexOf("machin") != -1){c1.text = "Truc?";}
   
    a1.text = "";
    d1.text = "";
   
//-----------------------------------------------------------------    Délais de la réponse
    zeTimer.delay = zedelais[Math.floor(Math.random()*zedelais.length)];
    zeTimer.start();
}



Une idée de là où ça coince, svp?

Merci de vos conseils...

#2 dldler

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 4163 messages

Posté 26 November 2015 - 10:02 AM

C'est un simple petit souci de compréhension de base.

Tu penses, apparemment, que le code est associé à chaque frame.
C'est faux.
Le code est exécuté quand tu passes sur une frame, et les fonctions sont déclarées au niveau global. C'est très différent.

Du coup, voilà ce qui se passe :
- arrivée sur la frame 1, pose de l'écouteur (déclenchant la fonction clavier_01) sur le champ a1 et mémorisation des fonctions
- je tape quelque chose puis touche entrée…
- l'écouteur lance la fonction de rappel clavier_01
- la fonction teste le texte saisi, répond, fait un nettoyage du champ a1
- je peux jouer jusqu'à ce que je passe à la frame 2 avec le mot clé mode
- arrivée sur la frame 2, pose de l'écouteur (déclenchant la fonction clavier_02) sur le champ a1 et mémorisation des fonctions
- je tape quelque chose puis touche entrée…
- l'écouteur, le premier posé, qui est toujours actif, lance la fonction de rappel clavier_01
- la fonction teste le texte saisi, répond, fait un nettoyage du champ a1
- l'écouteur, le second posé, lance la fonction de rappel clavier_02
- problème : la fonction clavier_01 a tout nettoyé, le champ a1 est vide. Ce qui explique que tu obtiens toujours une réponse au hasard…

Il y a d'autres signes qui montrent que tu penses que le code est cloisonné par image : la répétition de tes déclarations par exemple. Leur répétition est inutile, tu as même de la chance que ça ne rentre pas en conflit.


Deux choses :
- l'exposé de tes questions est clair, ta façon de penser est bonne, tu manques juste de pratique et de connaissance. Continue comme ça, c'est très agréable de t'aider.
- dans l'autre sujet, quand tu dis

Citation

Je préfère assembler des petits bouts afin de faire comme j'imagine, et d'y voir clair... puis comme tu dis, plus tard ce sera amélioré.
, je suis beaucoup moins fan ;-)
Ce n'est pas juste une question d'améliorer le code. C'est aussi une façon de le structurer. Et je pense beaucoup plus important de faire les bons choix dans la vision d'ensemble plutôt que d'y voir clair dans le code.

Par exemple dans ton cas : tu penses que le code de ton image 1 n'influence pas les événements de ton image 2, c'est un tort.
Code et frames sont indépendants et ne fonctionnement pas pareil.
On se sert de frames pour animer visuellement quelque chose, ou pour préparer des scènes différentes.
On se sert du code pour gérer des réactions aux actions de l'utilisateur (bon, en fait, on peut aussi animer, je suis bien placé pour le savoir mais ce n'est pas le sujet ici, crois moi).
En codant sur la timeline, on peut juste en profiter pour déclarer du code au moment choisit, quand on débute ça semble une bonne idée.
Avec de l'expérience on se rend vite compte que la déclaration de code peut toute se faire dès le début de l'animation. C'est ensuite la gestion des écouteurs qui va rendre un code opérant ou non, en fonction des actions de l'utilisateur.

Après, je ne sais pas si ton projet aura vraiment besoin de scène différentes, mais en l'état de ce que tu nous montre, c'est non.

Une seule image clé, un seul code.
Pour passer d'un mode à l'autre, il te faut juste :
- retirer l'ancien écouteur
- poser le nouvel écouteur

J'ai quelques autres conseils génériques à ta dispo si ça t'intéresse maintenant ;-)
Dans tous les cas, persévère.

#3 vegetalain

    Ceinture Orange

  • Members
  • PipPipPip
  • 34 messages

Posté 26 November 2015 - 14:33 PM

Merci pour ces conseils et ces encouragements, ça m'a permis de voir les choses différement ; je persévère donc ;-) .

En effet si l'image ne restreint pas le code c'est clair que ça crée un empilement d'instructions : c'est le chantier :eusa_doh:

Alors j'ai essayé de suivre tes conseils comme j'ai pu :roll: :

1. Virer la frame 2 et tout mettre sur la même frame (la première).
2. Ensuite j'ai ajouté un champ dynamic "zemode" où est inscrit si on est en mode 1, ou en mode 2... (par défaut j'ai mis "mode 1")
je l'ai d'abord mis en fin de fonction gogogo genre si tu tapes "mode 2" ça appelle la fonction du mode 2 mais ça ne marchait pas.
Alors finalement j'ai laissé l'inscription "mode 1" et "mode 2" dans les fonctions gogogo, mais j'ai mis la vérification au moment où l'on appuie sur la touche entrée. Comment ça, lorsque l'utilisateur valide son texte, ça vérifie en quel mode on est, et donc, quelle "conversation" gérer...

Donc tout est sur la même frame et apparement ça marche bien.

En mode 1 :
- je tape n'importe quoi et les phrases d'incompréhension dédiées sont lancées.
- je tape "coucou", il est capté.
- je tape "machin" (mot clé du mode 2), il n'est pas capté.
- Je tape "mode 2", il passe en mode 2.

En mode 2 :
- là quand je tape "machin" il le capte :D !!!!!!!!!
- quand je tape "coucou", il l'ignore puisque ce n'est pas le bon mode x)
C'est pile le fonctionnement que je voulais, "séparer" des mots clés et des conversations...

Voilà donc ce que j'ai mis en Frame 1, Calque 2 :

//----------------------------------------------------------------
//                        BLABLA INITIAL DE BASE (mode 1)
//----------------------------------------------------------------
SoundMixer.stopAll();
//----------------------------------------------------------------
a1.addEventListener(KeyboardEvent.KEY_DOWN, clavier_01);
function clavier_01(event:KeyboardEvent):void {
    if (event.keyCode == Keyboard.ENTER) {
        if (zemode.text == "mode 1"){gogogo_01();}
        if (zemode.text == "mode 2"){gogogo_02();}
    }
}
 
function gogogo_01():void {
var aok: String = a1.text;
//-----------------------------------------------------------------    RIEN DANS LA BASE  
    var okunide01:Array = ["De quoi?", "Je ne comprends pas.", "pardon??"];
    var saispas01:String = okunide01[Math.floor(Math.random()*okunide01.length)];  
    c1.text = saispas01;
 
//-----------------------------------------------------------------    Conversation standard
    if(aok.indexOf("coucou") != -1){c1.text = "Salut?";}
 
//-----------------------------------------------------------------    Passage en Mode 2
    if(aok == "mode 2"){zemode.text = "mode 2";}
 
//-----------------------------------------------------------------    Nettoyage des champs
    a1.text = "";
    d1.text = "";
   
//-----------------------------------------------------------------    Délais de la réponse
    zeTimer.delay = zedelais[Math.floor(Math.random()*zedelais.length)];
    zeTimer.start();
}
 
//----------------------------------------------------------------
//                        BLABLA SECONDAIRE (mode 2)
//----------------------------------------------------------------
function gogogo_02():void {
var aok2: String = a1.text;
//-----------------------------------------------------------------    RIEN DANS LA BASE  
    var okunide02:Array = ["Erreur truc.","Je n'ai rien à ce sujet.","Aucune info disponible."];
    var saispas02:String = okunide02[Math.floor(Math.random()*okunide02.length)];  
    c1.text = saispas02;
 
//-----------------------------------------------------------------    Conversation standard
    if(aok2.indexOf("machin") != -1){c1.text = "Machin reconnu !!";}
 
//-----------------------------------------------------------------    Passage en Mode 1
    if(aok2 == "mode 1"){zemode.text = "mode 1";}
 
//-----------------------------------------------------------------    Nettoyage des champs
    a1.text = "";
    d1.text = "";
   
//-----------------------------------------------------------------    Délais de la réponse
    zeTimer.delay = zedelais[Math.floor(Math.random()*zedelais.length)];
    zeTimer.start();
}

Je n'ai pas touché au code gérant l'affichage typewriter et le son...

Mais si tout est sur la même frame, ça me pose une autre question : quelle est la limite de lignes pour "1" frame? Non pas que je compte écrire un milliard de mots clés mais ... si tout est au même endroit ça va faire pas mal de trucs !!

#4 dldler

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 4163 messages

Posté 26 November 2015 - 14:58 PM

:)
Bravo, déjà.

Pour le nombre de lignes, je ne sais plus, mais tu as de la marge. Les codes de 500 lignes ne sont pas rares.
Après, tu peux t'amuser à fragmenter ton code en différents morceaux, en créant par exemple plusieurs calques, par thématiques, comme ça tu restes toujours sur l'image une mais tu si tu es bien organisé, tu peux plus facilement t'y retrouver.
Mais si tu persévères dans la voie de la force du code, petit scarabée, tu entendras vite parler de programmation orientée objets, et donc de classes. Chaque classe est un code qui décrit le comportement d'un type d'objet, et on l'écrit dans un fichier texte indépendant.


Maintenant, dans tes codes, essaye 2 choses :

1
- créer de toutes petites fonctions utiles qui t'aideront à écrire un code principal plus clair.
Par exemple, au lieu de :
var saispas01:String = okunide01[Math.floor(Math.random()*okunide01.length)];
…écris une fonction choisir_dans() qui fait le job.
Dans ton code principal, ça ne fera plus que :
var saispas01:String = choisir_dans(okunide01);

var saispas02:String = choisir_dans(okunide02);

La fonction choisir_dans() ferait ceci :
function choisir_dans(liste:Array):String {
   return liste[Math.floor(Math.random()*okunide01.length)];}
 



2
Factoriser le code
Ça veut dire s'arranger pour que deux codes très semblables, voir identiques, soient regroupés. Ça facilite les modifications, les enrichissements du code, et surtout les déclinaisons. Ça se repère facilement : quand tu as besoin de numéroter des variables, c'est que généralement tu devrais factoriser.
En l'état, imagine si tu veux coder 3, 4, 50 modes différents ? Tu vas devoir écrire les fonctions, déclarer les variables pour chaque mode ?


Je rajoute un 3 :
Sors les déclarations de tes variables en dehors de tes fonctions si elles sont utiles tout le temps (de toute façon, si tu commence à factoriser, ça deviendra vite obligatoire). Et même si tu ne factorises pas, une seule variable doit bien pouvoir suffire la plupart du temps. Après tout, quand tu traites le mode 2, tu ne traites pas le mode 1, donc il n'y a qu'un jeu de variables qui sert à chaque fois.

Je te passe un petit test, ou tu peux aller regarder par curiosité. Ce n'est peut être pas un code pour toi tout de suite, et il n'est sans doute pas adapté au développement de ton projet, mais ça devrait te montrer comment on procède en général.

Fichier(s) joint(s)

  • Fichier joint  test.fla   77.5 Ko   1 téléchargement(s)


#5 vegetalain

    Ceinture Orange

  • Members
  • PipPipPip
  • 34 messages

Posté 29 November 2015 - 05:41 AM

Merci de ces conseils. J'ai déjà réparti sur plusieurs calques l'as3, les variables (pas toutes), la validation du champs, les deux modes, etc... on y voit effectivement "plus clair" :mrgreen: . J'ai aussi ouvert par curiosité le fichier fla et comme tu disais ce code ne me correspond pas encore, il y a bien moins de ligne à mon goût et... je m'y retrouve moins, je sais pas... mais je le garde sous le coude, :roll: ...

Aujourd'hui, mode détente : là je suis en train de remplir mon bot avec des infos (mode 2) avec des connaissances générales (puisque je voulais destiner ce mode à ça), le plus dur sera pour la fin, la conversation de base et pire encore, le suivi d'une conversation (pensant consacrer une frame à une conversation c'est sur les frames que je comptais mais là grâce à toi je vais éparpiller les fonctions sur les calques)... A ce titre je vais voir ce qu'est exactement la factorisation quand j'aurai le temps.

Bref, plein de trucs intéressants à venir :smile:

Bon dimanche en attendant !!



1 utilisateur(s) li(sen)t ce sujet

0 membre(s), 1 invité(s), 0 utilisateur(s) anonyme(s)

authorised training centre

Centre de Formation Mediabox - Adobe et Apple Authorised Training Center.

Déclaré auprès de la Direction du Travail et de la Formation Professionnelle

Mediabox : SARL au capital de 62.000€ - Numéro d'activité : 11 75 44555 75 - SIRET : 49371646800035

MEDIABOX, 23, rue de Bruxelles, 75009 PARIS

FFP