blogorama
Accueil Date de création : 08/06/07 Dernière mise à jour : 28/01/10 21:47 / 17 articles publiés
 

Pourquoi ce blog ?  posté le jeudi 28 janvier 2010 21:47

 

Découvrez mon nouveau site sur la création dans SL

 

J'ai découvert second life il y a quelques mois et après quelques temps d'exploration je me suis lancé dans la construction. Les outils proposés sont suffisamment puissants mais snas égaler des logiciels dédiés comme 3D Studio ou Maya. Une chose que l'on rencontre rapidement dans la construction sur second life est le besoin d'animation. Celle-ci s'effectue au travers de script écrits en LSL, Linden Script Langage. Un langage de script assez complet qui adopte la syntaxe du C. J'ai remarqué rapidement que les scripts sont un peu le parent pauvre pour les utilisateurs de SL. Il semble réservé aux programmeurs et faire peur à la plupart. J'ai créé ce blog pour démystifier cet aspect de SL. J’ai aussi remarqué que la documentation existante est toute en langue anglaise et n’est pas très fournie.

Je vais donc essayer dans ce blog de présenter ce langage au travers d’exemples simples, et de le rendre abordable même à ceux qui n’ont jamais programmé. J’espère éveiller des vocations et des réactions.

lien permanent

Tutorial 15 toboggan 3/3  posté le lundi 15 octobre 2007 20:53

 

Suite du tutorial 14 (je viens de découvrir les limites de ce blog en étant obligé de découper ce tutorial en deux parties)...

 

Voyons maintenant le code de la ball :

vector position; // Position de depart
string animation; // Nom de l'animation
key AgentKey; // Clef de l'avatar
integer ecoute; // ecoute du chat
integer canal; // canal d'ecoute
integer canal_de_ball;  // Canal de reponse
rotation rot; // rotation initiale

initialisations () {

    // Animation
    animation = "sit knees up2";
    // Changement du texte du menu
    llSetSitText("Glisser");
    // Positionnement de l'animation
    llSitTarget(<0.0,0.0,.5>, ZERO_ROTATION);
    // Canaux
    canal = 37;
    canal_de_ball = 38;
    // Memorisation de la position
    position = llGetPos();
    rot = llGetRot();
}

depart ( ) {

    // Boule visible
    llSetAlpha(1.0, ALL_SIDES);
    // Passage en non physique
    llSetStatus(STATUS_PHYSICS, FALSE);
    // Retour de la boule au depart
    llSetPos (position );
    // Rotation
    llSetRot(rot);
}

default {

    on_rez(integer start_param) {
        // Initialisations
        initialisations();
        // Memorisation du canal d'ecoute
        canal = start_param;
        // Changement d'etat
        state attente;
    }
}

state attente {

    // Entree dans l'etat
    state_entry() {
        // Activation de l'ecoute du toboggan
        ecoute = llListen(canal,"",NULL_KEY,"");
        // Mise en route du timer
        llSetTimerEvent(120);
        // Depart
        depart();
    }

    // Atteinte du bas du toboggan determine
    // avec la collision avec le sol
    land_collision (vector position) {
        // Avatar debout
        llUnSit(AgentKey);
    }

    // Detection d'un changement
    changed(integer change) {
        // Test de changement dans les liaisons
        if (change & CHANGED_LINK) {
            // Determination de la clef de l'avatar
            AgentKey = llAvatarOnSitTarget ();
            // Un avatar est present ?
            if (AgentKey) {
                // Permission d'animation
                llRequestPermissions (AgentKey, PERMISSION_TRIGGER_ANIMATION);
                // Passage en physique et interdiction des rotations
                llSetStatus (STATUS_PHYSICS , TRUE);
                llSetStatus(STATUS_ROTATE_Y | STATUS_ROTATE_X | STATUS_ROTATE_Z, FALSE);
                // Impulsion
                llApplyImpulse(llGetMass()*<3.0,0.0,0.0>, TRUE);
                // Boule invisible
                llSetAlpha(0, ALL_SIDES);
            }
            else {
                // Determination de l'animation en cours
                string anim = llGetAnimation(AgentKey);
                // Arret eventuel de l'animation
                if(anim == "animation")
                    llStopAnimation(anim);
                // Depart
                depart();
            }
        }
    }

    // Permission accordee
    run_time_permissions(integer permissions) {
        if(permissions == PERMISSION_TRIGGER_ANIMATION) {
            // Arret de l'animation par defaut
            llStopAnimation("sit");
            // Animation
            llStartAnimation(animation);
        }
    }

    // Ecoute
    listen(integer channel, string name, key id, string message) {
        if (message == "Meurs")
            llDie();
        else if (message == "Vis")
            llSetTimerEvent(120);
        else if (message == "Positions") {
          // Memorisation de la position
        position = llGetPos();
        rot = llGetRot();

            // Envoi des positions au toboggan
            llSay (canal_de_ball, (string)position + "|" + (string)rot);
        }
    }

    // Delai ecoule
    timer ( ) {
        // Suicide
        llDie();
    }
}

Une grande partie de ce code a déjà été décrit dans le tutorial précédent. Je vais donc me contenter de commenter les nouveautés.

On va s’intéresser en particulier l’événement on_rez qui se déclenche lors de la création de la ball. On procède alors aux initialisations, en particulier la mémorisation de la position et de la rotation. On récupère également le canal d’écoute qui se retrouve dans le paramètre de l’événement. Ensuite on passe à l’état attente.

A l’entrée dans cet état on active l’écoute du toboggan. On déclenche un timer réglé à 120 secondes. S’il ne se produit aucun changement au bout de ce délai l’événement timer se produit et la fonction llDie supprime la ball. Ensuite on appelle la méthode depart qui est identique à celle du précédent tutorial.

Comme nouveauté nous trouvons l’écoute du toboggan. Le message « Meurs » entraine l’exécution de la fonction llDie pour suicider la ball. Le message « Vis » réinitialise le timer pour une nouvelle durée de 120 secondes. Enfin le message « Positions » provoque l’envoi des coordonnées au toboggan dans le format qu’il s’attend à recevoir.

Mode opératoire : commencez par créer le toboggan et son script. Ensuite créez la ball, en la nommant bien « ball », et son script et mettez là dans votre inventaire. Faites enfin glisser la ball de votre inventaire dans le contenu du toboggan. A la première touche du toboggan activez l’option « Glissade » pour créer la ball. Ajustez ensuite celle-ci correctement. Touchez alors le toboggan et choisissez l’option « Position » pour mémoriser la position de la ball. Votre toboggan est prêt à l’emploi J.

lien permanent

Tutorial 14 Toboggan 2/3  posté le lundi 15 octobre 2007 20:50

Dans le précédent tutorial je vous ai proposé un toboggan et je vous avais promis une version plus élaborée qui pallie les défauts les plus évidents. En particulier le fait que la ball ne soit pas solidaire du toboggan peut poser quelques problèmes lors des déplacements. Sans parler de la perte éventuelle de la ball.

Je vous propose donc une version plus élégante dans laquelle la ball est contenue dans le toboggan. Un clic sur celui-ci fait apparaître un menu avec trois options :

Glissade

Stop

Position

Cette option permet de faire apparaître la ball

Cette option fait disparaître la ball

Cette option permet de mémoriser la position et la rotation de la ball

D’autre part la ball ne peut survivre sans le toboggan. Celui-ci envoie une information cyclique, sans cette information la ball se suicide.

On se retrouve avec deux scripts : un dans le toboggan et un dans la ball.

Le toboggan doit savoir effectuer les opérations suivantes :

Ø      créer une ball en la positionnant correctement,

Ø      supprimer la ball,

Ø      demander à la ball sa position et sa rotation et mémoriser ces informations,

Ø      envoyer une information cyclique à la ball pour lui demander de survivre.

Voici le code correspondant à ces objectifs pour le toboggan :

integer canal_ball ; // Canal pour parler a la ball
integer canal_de_ball ; // Canal pour parler au toboggan
integer canal_menu ; // Canal pour le menu
integer ecoute ; // Ecoute
list menu;  // Options du menu
vector offsetPos ; // Offset de positionnement
rotation offsetRot ;    // Offset de rotation

// Initialisation du script
initialisations () {

    canal_ball = 37;
    canal_de_ball = 38;
    canal_menu = 47;
    menu =["Glissade" , "Stop" , "Position" ];
    offsetPos = <0.0,0.0,1.0>;
}

// Initialisation de la ball

rez_ball( ) {

    // Suppression eventuelle
    llSay ( canal_ball , "Meurs" );
    // Calcul du deplacement et de la rotation
    vector tobPos = llGetPos ();
    rotation tobRot = llGetRot ();
    vector DestPos = (offsetPos * tobRot ) + tobPos ;
    rotation DestRot = offsetRot * tobRot ;
    // Creation de la ball
    llRezObject ( "ball", DestPos , ZERO_VECTOR , DestRot , canal_ball );
    // Activation du timer
    llSetTimerEvent ( 60.0);
}

// Etat par defaut
default {

    // Entree de l'etat
    state_entry( ) {
        initialisations ();
    }

    // Reinitialisation
    on_rez( integer start_param ) {
        initialisations ();
    }

    // Touche
    touch_start (integer total_number ) {
        // Suppression de l'ecoute eventuelle
        llListenRemove ( ecoute );
        // Mise en place de l'ecoute
        ecoute = llListen (canal_menu , "", NULL_KEY , "");
        // Affichage du dialogue
        llDialog ( llDetectedKey (0), "Choisissez une option", menu, canal_menu );
    }

    // Stimulation reguliere de la ball
    timer ( ) {
        // Message pour la ball
        llSay ( canal_ball , "Vis" );
    }

    // Ecoute
    listen (integer channel, string name, key id, string message ) {
        // Affichage de l'option choisie
        llWhisper ( 0, name + " a choisi l'option '" + message + "'." );
        // Suppression de l'ecoute
        llListenRemove ( ecoute );
        // Selection selon l'option
        if (message == "Glissade" ) {
            // Affichage d'initialisation
            llWhisper ( 0, "Initialisation du toboggan");
            // Initialisation de la ball
            rez_ball( );
        }
        else if (message == "Stop" ) {
            // Suppression de la ball
            llSay ( canal_ball , "Meurs" );
            // Arret du timer
            llSetTimerEvent ( 0.0);
        }
        else if (message == "Position" ) {
            // Ecoute de la ball
            ecoute = llListen (canal_de_ball , "", NULL_KEY , "");
            // Demande positions
            llSay (canal_ball, "Positions" );
        }
        else if (llGetSubString (message, 0, 0) == "<" ) {
            // Reception des positions
            list pos = llParseString2List (message, ["|"], []);
            offsetPos = (vector )llList2String (pos , 0) - llGetPos ();
            offsetRot = (rotation )llList2String (pos , 1) / llGetRot ();
            llWhisper ( 0, "Memorisation de la position " + (string )offsetPos + " " + (string )offsetRot );
        }
    }
}

Sept variables nous sont nécessaires :

Variable

Type

Rôle

canal_ball

integer

Canal du toboggan vers la ball

canal_de_ball

integer

Canal de la ball vers le toboggan

canal_menu

integer

Canal pour le dialog

ecoute

integer

Mémorisation de l’écoute pour sa suppression

menu

list

Données du dialog

offsetPos

vector

Offset de positionnement de la ball

offsetRot

votation

Offset de rotation de la ball

La méthode initialisations permet de renseigner la valeur des canaux du chat et les données du Dialog. Les offset ont au départ une valeur nulle et l’écoute sera renseignée au moment nécessaire, c’est-à-dire lors de la création de l’écoute.

Une méthode intéressante est rez_ball qui permet de créer la ball. On commence par supprimer une ball éventuellement présente en envoyant un message de suicide. On calcule ensuite la position et la rotation de la future ball en se basant sur les informations de positionnement et de rotation du toboggan et de la valeur des offset. Je laisse les formules mathématiques aux amateurs de quaternions et autres fantaisies de ce genre pour en venir directement à l’importante fonction llRezObject. Celle-ci permet de créer un objet, ou plus exactement une instance d’un objet, parce que l’objet correspondant doit déjà exister dans l’objet qui contient le script. En d’autres termes dans notre cas la ball est déjà contenu dans le toboggan, on se contente d’en créer une instance. Observez les paramètres de cette fonction :

Paramètre

Type

Fonction

Inventory

string

Elément de l’inventaire à instancier

Pos

vector

Position de création

Vel

vector

Vélocité de l’objet créé

Rot

rotation

Rotation de création

Param

integer

Paramètre libre

Dans notre cas le premier paramètre correspond au nom de la ball contenue dans le toboggan. Le second et quatrième paramètres nous permettent d’ajuster la position et la rotation de la ball. Nous ignorons le troisième paramètre parce que nous voulons une ball immobile. Enfin nous profitons du dernier paramètre pour transmettre le canal d’écoute.

Tous les Rezzers que vous rencontrez sur sl sont fondés sur cette fonction ou sa sœur llRezAtRoot. Par exemple une maison imposante est découpée en morceaux et recréée sur place avec un Rezzer. Vous pouvez aussi imaginer un aménagement d’appartement modulable…

Je dois toutefois préciser que ce rezzer m’a passablement occupé ces derniers temps et mes amis sur sl s’amusaient de me voir en train de m’énerver sur mon toboggan. J’avais beau analyser mon code je ne trouvais pas la faille. Jusqu’au moment où j’ai eu l’idée de faire un essai avec des objets simples plutôt qu’avec les prims torturées de mon toboggan. Et là grosse surprise : tout fonctionnait parfaitement ! J’avais passé beaucoup de temps à chercher des erreurs qui n’existaient pas… Moralité : si vous voulez créer un rezzer utilisez plutôt une prim sans trop de modifications sinon vous risquer de galérer comme je l’ai fait avec des positionnements aléatoires. Il m’a suffit d’ajouter un cube à mon toboggan et de le définir comme root et tout s’est bien passé ensuite…

La dernière action de la méthode initialisations est de déclencher un timer réglé à 60 secondes pour envoyer une impulsion régulière à la ball pour lui demander de vivre. Ce que vous retrouvez dans la fonction timer avec le message « Vis » sur le canal de la ball.

Le reste du code ne présente pas de nouveauté. L’événement touch_start commence par supprimer une écoute éventuelle, mets en route l’écoute pour le dialog, et affiche le dialog.

L’événement listen récupère l’action de l’utilisateur :

Option

Action

Glissade

Mise en œuvre de la méthode rez_ball

Stop

Envoi du message « Meurs » à la ball

Position

Ecoute de la ball et envoi du message « Positions » à la ball

Lors de l’écoute de la ball le seul message qui peut revenir est celui qui contient les coordonnées. On teste le message avec la fonction llGetSubString qui permet d’extraire une sous-chaîne d’une chaîne en transmettant l’index du caractère de début et l’index du dernier à extraire. Pour extraire le premier caractère il faut mettre 0 pour les deux paramètres. Les coordonnées sont transmises sous le format string séparées par le caractère « | ». La fonction llParseString2List permet de récupérer dans une list les éléments séparés par le caractère passé en paramètre (en fait une liste de séparateurs au format string). Il suffit ensuite d’extraire les coordonnées avec un cast (transformation de type) et de les combiner aux coordonnées du toboggan pour obtenir les offset et les mémoriser.

Suite au tutorial suivant...

 

lien permanent

Tutorial 13 Toboggan 1/3  posté le jeudi 06 septembre 2007 20:15

Les tutoriaux que je vous ai proposés jusque là n’incluaient pas trop d’éléments d’animation, juste quelques portes qui s’ouvrent ou se ferment et un avatar qui dort ou qui danse. Nous allons essayer maintenant de déplacer un avatar. Je me suis intéressé ces derniers temps aux toboggans. J’en ai rencontré plusieurs sur sl, la plupart situés au bord d’une piscine. La technique de déplacement de l’avatar me semblait être pratiquement toujours la même. Une ball en haut du toboggan prend en charge l’avatar pour initier une animation et permettre à l’avatar de glisser. Vous avez sans doute remarqué que la gravité sur sl agit sur tous les objets « physiques », dont les avatars font partie. Lorsque vous marchez sur un terrain en pente vous avez tendance à courir. Lorsque vous sautez d’un toit vous vous écrasez lamentablement au sol. On pourrait donc penser qu’un toboggan n’est après tout qu’un plan incliné et que l’avatar ne peut rien faire d’autre que glisser. Mais vous n’avez qu’à faire l’expérience pour constater que le problème n’est pas aussi simple. La première difficulté est qu’un avatar est en principe debout, il faut donc dans un premier temps l’obliger à s’asseoir. Nous avons déjà abordé cette question de l’animation dans de précédents tutoriaux. Il suffit de prévoir une ball avec un SitTarget et une animation., demander l’autorisation et lancer l’animation. Mais ce n’est pas parce qu’un avatar s’assoit qu’il va pour autant glisser dans la pente, il faut un peu l’aider. Pour cela il faut lui donner une impulsion vers l’avant. Il existe pour cela une fonction nommée llApplyImpulse qui va nous permettre de propulser l’avatar dans la pente. Avec cette pichenette l’avatar commence à glisser mais si nous lui laissons la totale liberté dans les rotations il y a de grandes chances pour qu’il bascule d’une façon pour le moins inélégante. C’est pour cette raison que nous allons verrouiller les rotations. De cette façon l’avatar n’a d’autre choix que de glisser sagement dans le toboggan. Mais que se passe-t-il lorsqu’il atteint le sol ? Il serait bien qu’arrivé là il se relève et que la ball aille sagement reprendre sa place en haut du toboggan pour une nouvelle glissade. Nous devons donc détecter l’arrivée au sol, ce qui se fait grâce à l’événement land_collision.

Pour ce tutorial il va vous falloir créer un toboggan, ce qui est après tout un bon exercice de build, vous pouvez voir sur la photo celui que j’ai réalisé pour l’occasion, en bois et en verre. Prévoyez une pente de 45% pour favoriser la glissade. Vous devez aussi créer une ball pour loger le script et l’animation. Pour cette dernière j’ai utilisé une free qui s’appelle « sit knees up2 », si vous voulez essayer la même vous devriez pouvoir la trouver facilement dans les boutiques free, je peux aussi vous la donner en ligne en m’envoyant un IM (Bestmomo Lagan), je peux aussi vous montrer le toboggan en action… Le positionnement de la ball doit être relativement bien ajusté pour que votre toboggan fonctionne. Voici le script à mettre dans la ball :

vector position; // Position de depart
string animation; // Nom de l'animation
key AgentKey; // Clef de l'avatar

initialisations()
{

    // Memorisation position de depart;
    position = llGetPos();
    // Rotation à 0
    llSetRot(ZERO_ROTATION);
    // Animation
    animation = "sit knees up2";
    // Changement du texte du menu
    llSetSitText("Glisser");
    // Positionnement de l'animation
    llSitTarget(<0.0,0.0,.5>, ZERO_ROTATION);
}

depart()
{
    // Boule visible
    llSetAlpha(1.0, ALL_SIDES);
    // Passage en non physique
    llSetStatus(STATUS_PHYSICS, FALSE);
    // Retour de la boule au depart
    llSetPos(position);
    // Rotation à 0
    llSetRot(ZERO_ROTATION);
}

default
{
    // Entree dans l'etat
    state_entry()
    {
        initialisations();
        state attente;
    }

    // Reset du script
    on_rez(integer start_param)
    {
        initialisations();
        state attente;
    }

}

state attente
{
    // Entree dans l'etat
    state_entry()
    {
        depart();
    }

    // Atteinte du bas du toboggan determine avec la collision avec le sol
    land_collision(vector position)
    {
        // Avatar debout
        llUnSit(AgentKey);
    }

    // Detection d'un changement
    changed(integer change)
    {
        // Test de changement dans les liaisons
        if (change & CHANGED_LINK)
        {
            // Determination de la clef de l'avatar
            AgentKey = llAvatarOnSitTarget();
            // Un avatar est present ?
            if (AgentKey)
            {
                // Permission d'animation
                llRequestPermissions (AgentKey, PERMISSION_TRIGGER_ANIMATION);
                // Passage en physique et autorisation des rotations
                llSetStatus(STATUS_PHYSICS, TRUE);
                llSetStatus(STATUS_ROTATE_Y | STATUS_ROTATE_X | STATUS_ROTATE_Z, FALSE);
                // Memorisation position de depart;
                position = llGetPos();
                // Impulsion
                llApplyImpulse(llGetMass()*<3.0,0.0,0.0>, TRUE);
                // Boule invisible
                llSetAlpha(0, ALL_SIDES);
            }
            else
            {
                // Determination de l'animation en cours
                string anim = llGetAnimation(AgentKey);
                // Arret eventuel de l'animation
                 if(anim == "animation")
                     llStopAnimation(anim);
                // Depart
                depart();
            }
         }
    }

    // Permission accordee
    run_time_permissions(integer permissions)
    {
        if(permissions == PERMISSION_TRIGGER_ANIMATION)
        {
            // Arret de l'animation par defaut
            llStopAnimation("sit");
            // Animation
            llStartAnimation(animation);
        }
    }
}

Voyons le fonctionnement de ce code. Nous avons trois variables globales :

Ø      position pour mémoriser la position initiale de la ball

Ø      animation pour conserver le nom de l’animation

Ø      AgentKey pour loger la clef de l’avatar.

J’ai prévu comme d’habitude une méthode d’initialisation qui permet de :

Ø      mémoriser la position de départ de la ball grâce à la fonction llGetPos

Ø      fixer la rotation par défaut de la ball

Ø      déterminer l’animation à utiliser

Ø      changer le texte du menu pour afficher « Glisser »

Ø      positionner l’avatar pour l’animation

Après cette initialisation on passe dans l’état attente. Une méthode nommée depart qui est appelée au démarrage du script et à chaque fois qu’un avatar libère la ball en fin de glissade. Dans cette méthode nous prévoyons de :

Ø      rendre la ball visible avec la fonction llSetAlpha

Ø      passer la ball en mode physique avec la fonction llSetStatus

Ø      positionner la ball à son emplacement initial

Ø      mettre la rotation par défaut

Le mode physique est indispensable pour mettre en jeu la gravité et permettre la glissade. Par contre il faut désactiver cette propriété lorsque la ball attend en haut du toboggan sinon elle n’aura pas trop envie de rester en place J . Il est également judicieux de plus voir la ball lors de la glissade.

Arrivé à ce stade le script attend un changement. Celui-ci est détecté avec l’événement changed. Nous avons déjà abordé ce sujet précédemment et je n’insisterai pas. On récupère la clef de l’avatar avec la fonction llAvatarOnSitTaget, on demande la permission pour animer avec la fonction llRequestPermissions  La fonction llSetStatus permet ensuite de passer en mode physique et de verrouiller les rotations. Ensuite on mémorise la position de départ avec llGetPos.

Ensuite on propulse l’avatar avec la fonction llApplyImpulse. Voyons ses paramètres. Le premier fixe la valeur de l’impulsion. Un vecteur permet de fixer sa direction, ici juste sur l’axe X. J’ai rendu la valeur dépendante de la masse de l’avatar (récupérée avec la fonction llGetMass)  pour avoir une impulsion uniforme quel que soit son poids. Le second paramètre défini si les coordonnées sont globales ou locales. Dans notre cas nous choisissons évidemment local. Il ne reste plus qu’à rendre la boule invisible et c’est parti J.

Lorsque l’avatar arrive en bas il touche le sol, ce qui déclenche l’événement land_collision. L’avatar se remet alors debout grâce à la fonction llUnSit. Ce qui a pour effet également de déclencher l’événement changed mais cette fois aucun avatar n’est détecté. Nous stoppons alors l’animation en cours et appelons à nouveau la méthode depart pour réinitialiser le toboggan. Et ainsi de suite…

Tel quel ce toboggan fonctionne très bien. Mais il est présente quelques imperfections. La ball est forcément non liée au toboggan. En cas de déplacement de celui-ci il ne faut pas oublier cette particularité J. En cas de perte de la ball il faut également en recréer une a la main, la ball perdue ne se détruit pas automatiquement. Mais je réserve ces améliorations pour le prochain tutorial. Vous pouvez aussi faire des suggestions sur la direction que pourrait prendre cette réalisation.  En attendant bonnes glissades J.

lien permanent

Tutorial 12 Les Dialog  posté le mercredi 22 août 2007 20:39

 

Ce blog a pris son rythme de croisière pour les vacances. Les possibilités d'interaction dans SL sont un peu limitées. On peut entrer des données par l'intermédiaire du Chat. Mais si aucune donnée aléatoire est attendu il existe un moyen simple et élégant d'activer les scripts, les dialogues, ces menus au joli fond bleu qui apparaissent en haut a droite de l'écran pour créer une interactivité avec un jeu de boutons. Une seule fonction pour créer ces dialogues llDialog avec quelques paramètres dont vous trouvez la description ici :

 

http://www.lslwiki.net/lslwiki/wakka.php?wakka=llDialog

 

Pas mal d'explications ici, mais en anglais bien entendu... En résumé la fonction permet d'afficher le dialogue. Le premier paramètre représente l'id de l'avatar pour lequel ce dialogue doit être affiché. Le second représente le message qui doit être inscrit en tête. Le troisième contient les textes a afficher sur les boutons. C'est ce troisième paramètre le plus important, il a comme type une list. Nous avons déjà eu l'occasion d'en utiliser une. Je rappelle qu'il s'agit d'un groupe de données, dans notre cas un ensemble de string qui représentent ce qui doit être écrit sur les boutons, et pas la même occasion le nombre de boutons. Le dernier paramètre mérite une petite explication préliminaire, à savoir ce qui se passe lorsque l'avatar clique sur un bouton. Tout simplement le texte du bouton est envoyé sur un canal du chat, et c'est justement ce dernier paramètre qui définit le numéro du canal. Je rappelle le le canal général est le 0, surtout n'utilisez pas cette valeur sinon ça va s'afficher pour tout le monde

 

Une fois le dialogue mis en place, puisque le résultat du clic aboutit sur un canal du chat il faut mettre en place une écoute de ce canal avec la fonction llListen que vous connaissez déjà et définir l'action à accomplir selon la valeur sélectionnée. Pour l'exemple j'ai choisi une commande pour des vitres avec réglage de la transparence et de la couleur, tout simplement parce que j'en ai parlé récemment avec une amie qui a fait un superbe script sur le sujet. J'en reprends la trame principale en le simplifiant par souci pédagogique, entre autre... J'ai prévu un sous-dialogue pour avoir une approche complète. Le premier dialogue permet le réglage de la transparence, le second de la couleur avec possibilité de retour en arrière. Voici le code :

 

integer channel;
list menu;
list menu_couleurs;
vector blanc;
vector rouge;
vector vert;
vector bleu;

initialisations()
{

   channel = 27;
   menu = [ "Transparent", "20%", "40%", "60%", "80%", "Opaque", "Couleur..." ];
   menu_couleurs = [ "blanc", "rouge", "vert", "bleu", "...retour" ];
   blanc = <1.0,1.0,1.0>;
   rouge = <1.0,0.0,0.0>;
   vert = <0.0,1.0,0.0>;
   bleu = <0.0,0.0,1.0>;
   teinte(0);
}

teinte(float alpha)
{
   integer c;
   for (c = 1; c <= llGetNumberOfPrims(); c++)
   llSetLinkAlpha(c, alpha, ALL_SIDES);
}

couleur (vector coul)
{
   integer c;
   for (c = 1; c <= llGetNumberOfPrims(); c++)
   llSetLinkColor(c, coul, ALL_SIDES);
}

default
{
   state_entry()
   {
      initialisations();
      llListen(channel, "", NULL_KEY, "");
   }

   touch_start(integer total_number)
   {
      llDialog(llDetectedKey(0), "Choisissez une option", menu, channel);
   }

   listen(integer channel, string name, key id, string message)
   {
      if (llListFindList(menu + menu_couleurs, [message]) != -1)
      {
         if (message == "Couleur...")
            llDialog(id, "Choisissez une couleur", menu_couleurs, channel);
         else if (message == "...retour")
            llDialog(id, "Choisissez une option", menu, channel);
         else if (message == "Transparent")
            teinte(0.0);
         else if (message == "Opaque")
            teinte(1.0);
         else if (message == "20%")
            teinte(.2);
         else if (message == "40%")
            teinte(.4);
         else if (message == "60%")
            teinte(.6);
         else if (message == "80%")
            teinte(.8);
         else if (message == "blanc")
            couleur(blanc);
         else if (message == "rouge")
            couleur(rouge);
         else if (message == "vert")
            couleur(vert);
         else if (message == "bleu")
            couleur(bleu);
         } else
            llSay(0, name + " a choisi une option non valide '" + llToLower(message) + "'.");
      }
}

 

Ce code s'applique à un ensemble de prims liés, normalement des vitres. Si vous l'utilisé pour un prim isolé il ne se passera rien pour des raisons qui vont être explicitées plus loin. Voyons un peu l'utilité des différents champs :

 

Champ Type Fonction
channel integer canal du chat
menu list liste des options du menu général
menu_couleurs list liste des options du menu des couleurs
blanc vector vecteur du blanc
rouge vector vecteur du rouge
vert vector vecteur du vert
bleu vector vecteur du bleu

 

La méthode initialisations permet d'affecter les valeur de ces champs, elle est appelée au lancement du script, pour bien faire il faudrait aussi l'appeler en cas de reset mais je n'ai pas voulu alourdir le code.

 

La méthode teinte a pour objet de modifier l'alpha (transparence) des prims liés. Je rappelle que dans une liaison de prim il est affecté un numéro à chacun qui démarre à 1, alors qu'un prim isolé possède par défaut le numéro 0. Le paramètre de la méthode contient une valeur pour l'alpha qui doit se situer entre 0 (transparent) et 1 (opaque). Pour changer l'alpha de tous les prims nous avons besoin de connaître leur nombre, c'est la fonction llGetNumberOfPrims qui nous donne cette valeur. Ensuite il suffit d'utiliser une boucle for pour balayer toutes les valeurs et utiliser la fonction llSetLinkAlpha pour modifier l'alpha du prim dont le numéro correspond à la valeur de la variable c.

 

La méthode couleur suit le même principe mais le paramètre est un vecteur qui représente la couleur et la fonction utilisée est llSetLinkColor qui permet de changer la couleur de prims liés.

 

Cette intendance étant mise en place nous avons un seul état, celui par défaut default. Au départ du script (state_entry) nous activons l'initialisation et l'écoute sur le canal déterminé par la variable channel. C'est par ce canal que les informations vont passer du dialog au script. Dès qu'un avatar clique sur une vitre (touch_start) on active le menu principal avec la fonction llDialog. Pour déterminer quel avatar a cliqué nous utilisons la fonction llDetectedKey qui nous renvoie son id, nous prévoyons une phrase d'accueil, nous transmettons la list qui contient les options à afficher, en l'occurrence menu et enfin le canal par lequel transmettre l'information (channel). Lorsque l'avatar clique sur une des options l'événement listen est déclenché. C'est ici que nous allons trouver le coeur du script.

 

Il faut comprendre que cet événement sera déclenché aussi pour le sous-menu, celui des couleurs. Nous commençons par un test pour savoir si l'information transmise sur le canal du chat correspond à une des option des deux menus concernés. C'est l'objet de la fonction llListFindList qui renvoie l'index de la première instance de message dans les deux listes menu et menu_couleur. En cas d'échec la valeur -1 et renvoyée et on transmet une information d'erreur sur le chat. Dans le cas contraire on entame une longue série de tests pour savoir quelle option a été choisie. S'il s'agit d'un pourcentage (également transparent et opaque) on appelle la méthode teinte pour changer l'alpha. S'il s'agit d'un couleur on appelle la méthode couleur pour changer celle-ci. Par contre s'il s'agit de "Couleur..." il faut lancer le sous-menu en utilisant à nouveau la fonction llDialog mais cette fois avec les bons paramètres pour le dialogue des couleurs. Il est aussi prévu un bouton de retour au menu principal qui se contenter de relancer celui-ci.

 

Vous êtes maintenant parés pour faire de superbes dialogues avec un nombre quelconque de sous-dialogues. Comme vous pouvez le constater la technique à mettre en oeuvre est simple, un bon script pour cette fin de vacances...

 

Nouveauté !!!  J'ai créé un utilitaire qui génère le code automatiquement pour les dialogues , vous trouvez tout ça expliqué ici :

 

http://script.lsl.free.fr/dialog.htm

 

 

 

 

lien permanent