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

Tutorial 11 Les Sensor  posté le mercredi 01 août 2007 20:10

 

Dans Second Life un avatar peut transporter de multiples objets. Une façon simple de le faire est l'attachement. Comme ce nom l'indique l'objet est alors intimement lié à l'avatar et se déplace avec lui. Cet objet doit être NonPhysical. Qu'est-ce que cela veut dire ? Vous avez peut être remarqué lorsque vous créez des objets dans SL qu'il y a des attributs "physiques", c'est à dire liés à la gravité, en quelque sorte ces attributs permettent de donner un mode de déplacement réaliste à l'objet, comme s'il était dans le monde réel. Un tel objet ne peux pas être attaché à un avatar. Vous savez certainement attacher un objet à partir de votre inventaire. Mais vous pouvez aussi le réaliser par script avec la fonction llAttachToAvatar. Cette fonction à un seul paramètre qui détermine le lieu de l'attachement, vous trouvez tous les renseignement ici :

 

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

 

En particulier la liste des constantes pour les localisations. Pour détacher un objet vous avez la fonction inverse llDetachFromAvatar.

Une autre façon de déplacer des objets avec un avatar et de tout simplement leur demander de le suivre. Vous avez sans douté repéré certains avatars avec un objet qui flotte derrière eux : oiseau, dragon, papillon et autres bestioles. Pour réaliser cela il existe une fonctionnalité nommée Sensor. C'est à dire une façon pour un objet de détecter la présence d'un autre objet, en l'occurrence un avatar dans notre cas. Le wiki n'est pas très loquace sur ce sujet :

 

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

 

Seulement 3 fonctions et 2 événements. Le seul objet des 3 fonctions est de déclencher l'événement sensor qui est l'élément principal :

 

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

 

Pour ce tutorial je vous propose un script tout simple que vous positionnez dans l'objet qui doit suivre votre avatar. Voici le code :

 

// Offset
vector offset = <-1,0,0>;
// Delai de recherche du proprietaire en secondes
float delai = .4;
// Distance de recherche en metres
float distance = 20;
// Angle de recherche en radians
float angle = PI_BY_TWO;
// Delai du deplacement en secondes
float deplacement = .3;

default
{
   state_entry()
   {
      // Passage de l'objet en Physique, il a donc une masse
      // et subit les lois de la gravitation
      llSetStatus(STATUS_PHYSICS, TRUE);
      // Petite attente de 0,1 seconde
      llSleep(0.1);
      // Recupration de la Key du proprietaire
      key proprio = llGetOwner();
      // Cherche la position du proprietaire
      llSensorRepeat("", proprio, AGENT, distance, angle, delai);
   }

   sensor(integer total_number)
   {
      // Determination de la position du proprietaire
      vector pos = llDetectedPos(0);
      // Test de validite de la position
      if (pos != <0,0,0>)
      {
         // Offset de positionnement
         pos += offset;
         // Deplacement de l'objet
         llMoveToTarget(pos, deplacement);
      }
   }
}

 

A l'entrée dans le script (state_entry) la première instruction utilise la fonction llSetStatus. Cette fonction modifie les propriétés d'un objet. Par exemple on peut empêcher la rotation d'un objet sur un ou plusieurs axes. Vous trouvez tous les paramètres ici :

 

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

 

Dans notre cas on se contente de définir l'objet comme physique pour que son déplacement soit réaliste. La fonction llSleep se contente d'introduire une temporisation. Nous avons déjà utilisé la fonction suivant qui récupère la Key de l'avatar. La fonction suivante llSensorRepeat est plus intéressante, c'est elle qui définit les paramètres du sensor :

 

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

 

Cette fonction déclenche le sensor de façon répétitive. Elle possède plusieurs paramètres. Les trois premier permettent de déterminer l'objet à détecter : son nom, sa Key et son type. Les deux suivants concernent la zone de recherche : distance (range) et angle (arc). Le dernier paramètre définit la fréquence de la recherche en secondes. La plupars de ces paramètres ont été définis dans des variables globales pour une meilleure lisibilité du script.

L'événement sensor permet d'opérer la gestion du déplacement. Le paramètre de cet événement donne le nombre d'objets détectés dans la zone définie. Il ne nous est pas utile dans notre cas. La fonction suivante llDetectedPos fait partie du lot qui donne des informations sur les objets détectés :

 

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

 

Vous constatez qu'il y en a un certain nombre. Nous nous contentons de déterminer la position de l'avatar puisque cette information nous suffit pour pouvoir suivre ses déplacements. Après avoir vérifié la validité de cette position on déplace l'objet avec la fonction llMoveToTarget qui permet de déplacer un objet physique. L'offset sert à déterminer le positionnement par rapport à l'avatar.

 

lien permanent

Tutorial 10 Les Particles  posté le mercredi 04 juillet 2007 20:53

 

Je me suis intéressé aux Particles ces derniers jours. Je me suis demandé comment on créait tous ces effets particulièrement réalistes comme la fumée ou les feux d'artifice. Je suis tombé dans la documentation sur une seule fonction disponible avec un paramètre unique :

 

http://wiki.secondlife.com/wiki/LlParticleSystem

 

A la lecture de cette page on se dit que l'affaire n'est pas simple et qu'on est parti pour quelques heures de prise de tête, encore plus si l'anglais n'est pas vraiment une seconde nature, ce qui est mon cas. J'ai fait quelques essais, j'ai cherché des exemples. J'ai trouvé un peu de tout, avec deux axes principaux : soit une fonction à rallonge avec des variables à n'en plus finir qui alourdissent le script, ce qui est plutôt à éviter dans ce genre :

 

http://lslwiki.net/lslwiki/wakka.php?wakka=ExampleParticleScript

 

Soit une approche plus "à la demande" pour ceux qui savent déjà bien ce qu'ils veulent :

 

http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryKeknehvParticles

 

Aucune de ces deux approches ne m'ont vraiment satisfait et je ne pense pas vraiment être le seul dans ce cas quand je lis les questions sur les particles dans les forums. Le problème vient de l'abondance des éléments constitutifs du paramètre de la fonction llParticleSystem. On a un peu du mal à s'y retrouver et certaine explication sont un peu "ésotériques" au premier abord. A part ça le reste est simple, on peut avoir qu'un seul système de particules par prim, il est aligné sur l'axe Z dans le sens positif et il est constitué de sprites en 2D orientés vers la caméra. Il faut aussi savoir que les particles sont générées côté client, autrement dit sur votre PC.

A force de tourner cette histoire dans tous les sens et de mettre au point du code qui ne me satisfaisait toujours pas j'ai changé complètement d'optique. J'ai créé un logiciel qui génère automatiquement la fonction avec son paramètre. Je pense que pratiquement tous les scipteurs sur SL codent dans un éditeur externe. Bien sûr il y a toujours des masos qui aiment s'esquinter les yeux et user leur patience avec l'éditeur intégré mais bon... Comme la plupart d'entre vous je code en externe avec l'éditeur de Alphons van der Heijden dont je vous rappelle l'adresse de téléchargement :

 

http://www.lsleditor.org/

 

Alors la solution que je vous propose est aussi un programme externe qui présente les éléments du paramètre de la fonction d'une façon conviviale et génère le code qu'il suffit de copier et coller dans votre éditeur. Comme ce blog ne permet pas le téléchargement de fichiers j'ai créé un petit site complémentaire ou je présente sommairement le logiciel et où vous pouvez vous le procurer :

 

http://script.lsl.free.fr

 

Donc pour les détails concernant ce programme et ses fonctionnalités je vous renvoie à cette adresse. Ici je me contente de vous proposer un script de test tout simple :

 

default
{
   state_entry()
   {
      llParticleSystem([
         PSYS_PART_FLAGS, 0
         | PSYS_PART_INTERP_COLOR_MASK
         | PSYS_PART_EMISSIVE_MASK,
         PSYS_SRC_PATTERN,
         PSYS_SRC_PATTERN_ANGLE,
         PSYS_PART_START_ALPHA, 0.9,
         PSYS_PART_END_ALPHA, 0.5,
         PSYS_PART_START_SCALE, <0.1,0.1,0.0>,
         PSYS_PART_END_SCALE, <0.6,0.6,0.0>,
         PSYS_PART_START_COLOR, <0.7529412,0,0>,
         PSYS_PART_END_COLOR, <1,0.627451,0.4784314>,
         PSYS_PART_MAX_AGE, 10.0,
         PSYS_SRC_MAX_AGE, 100.0,
         PSYS_SRC_BURST_RATE, 0.1,
         PSYS_SRC_BURST_PART_COUNT, 1000,
         PSYS_SRC_ANGLE_END, 0.5,
         PSYS_SRC_ANGLE_BEGIN, 0.0,
         PSYS_SRC_BURST_RADIUS, 0.2,
         PSYS_SRC_OMEGA, <0,0,0.2>,
         PSYS_SRC_ACCEL, <0,0,0>,
         PSYS_SRC_BURST_SPEED_MIN, 0.2,
         PSYS_SRC_BURST_SPEED_MAX, 0.5]);
   }

   touch_start( integer num )
   {
      state off;
   }
}

state off
{
   state_entry()
   {
      llParticleSystem([]);
   }

   touch_start( integer num )
   {
      state default;
   }
}

 

Vous pouvez l'utiliser pour vos essais. Il suffit de le poser dans un objet. Quand vous le touchez ça démarre, la fois suivante ça s'arrête. Il vous suffit de copier la partie de code générée par le programme Particles et de le coller dans ce script au bon endroit.

lien permanent

Tutorial 9 Balançoire  posté le vendredi 29 juin 2007 20:16

 

J'ai découvert lsl il y a 3 mois lorsqu'une amie m'a demandée de l'aider à écrire un script dans Second life. Le but était d'animer une balançoire. Je pensais la tâche aisée étant donnée mon expérience en programmation. Mais c'était sans compter sur les particularités de lsl et de Second Life. J'ai galéré pendant deux jours pour trouver les éléments nécessaires et j'ai fulminé contre l'hégémonie de la langue anglaise au niveau de la documentation. Il en est sorti un script fonctionnel mais pas vraiment esthétique. Avec le recul je me rends compte de ses imperfections. Récemment dans le forum de jeuxonline (je ne peux que vous conseiller ce forum en français avec des personnes très compétentes et vraiment serviables) j'ai proposé ce script suite à une question. Voici le lien :

 

http://forums.jeuxonline.info/showthread.php?t=803732

 

On m'a très justement fait remarquer que mon script ne fonctionne plus lorsque la balançoire subit une rotation. Il était donc temps que je reprenne ce script pour le rendre à la fois plus élégant et plus efficace. Voici le code qu'il en est sorti :

 

//
// Balancoire Version 1.0
//
       par bestmomo
//

// Periode du mouvement en secondes
float Periode;
// Amplitude du demi mouvement en degres
float Amplitude;
// Amplitude sur l'axe X
float AmplitudeX;
// Amplitude sur l'axe Y
float AmplitudeY;
// Pas de changement
float Pas;
// Rotation de depart
rotation Rotdepart;
// Gestion du temps
float Temps;

initialisations()
{
   Periode = 4.0; // 4 secondes
   Pas = 0.2; // 0,2 secondes
   // Rotation de depart
   Rotdepart = llGetRot();
   // Rotation de depart Euler
   vector RotdepartEuler = llRot2Euler(Rotdepart);
   // Amplitude du mouvement en radians
   Amplitude = 40.0 * DEG_TO_RAD;
   // Amplitude sur l'axe X
   AmplitudeX = Amplitude * llCos(RotdepartEuler.z);
   // Amplitude sur l'axe Y
   AmplitudeY = Amplitude * llSin(RotdepartEuler.z);
}

default
{
   touch_start(integer total_number)
   {
      // Mise en marche
      state marche;
   }
}

state marche
{
   state_entry()
   {
      initialisations();
      // Demarrage du timer
      llSetTimerEvent(Pas);
   }

   touch_start(integer total_number)
   {
      // Retour position initiale
      llSetRot(Rotdepart);
      // Reset du script
      llResetScript();
   }

   timer()
   {
      // Incrementation du temps
      Temps += Pas;
      // Calcul des angles
      float AngleX = AmplitudeX * llSin((TWO_PI / Periode) * Temps);
      float AngleY = AmplitudeY * llSin((TWO_PI / Periode) * Temps);
      // Calcul de la rotation
      rotation Rot = Rotdepart * llEuler2Rot( <AngleX, AngleY, 0>);
      // Application de la rotation
      llSetRot(Rot);
   }

}

 

Au niveau de la construction le script doit se trouver dans le root, au niveau de l'axe. Le prim correspondant doit être centré et ne doit pas subir de rotation sur les axes X et Y. Le plus simple est de prévoir un box que vous redimensionnez, quitte à le rendre transparent ensuite pour conserver uniquement les cordes. C'est ce que j'ai fait sur mon exemple que vous pouvez voir sur la photo. Cette fois la balançoire peut être déplacée sans souci à condition évidemment de la conserver horizontale ! Ce qui paraît très naturel pour une balançoire.

Le mouvement d'une balançoire est pendulaire, autrement dit c'est une fonction sinusoïdale. J'ai vu sur SL des balancelles avec un mouvement très fluide mais désespérément linéaire. Il est facile de réaliser ce type d'animation avec la fonction llTargetOmega :

 

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

 

Mais le soucis de réalisme doit nous éloigner de cette solution qu'il faut réserver à des mouvements linéaires du genre manège. LSL possède une librairie mathématique relativement complète :

 

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

 

On y trouve en particulier les fonctions trigonométriques qui vont nous servir pour la balançoire : llCos pour trouver le cosinus et llSin pour le sinus. Voyons un peu le code...

Il y a un certain nombre de variables globales. La Periode représente le rythme du balancement, c'est le temps mis pour accomplir un mouvement de balancement complet. L'Amplitude représente la dimension du balancement (en fait la moitié de celui-ci) en degrés. Ensuite viennent deux amplitudes : AmplitudeX et AmplitudeY. Ces deux valeurs sont nécessaires pour gérer les rotations de la balançoire lors de ses différents positionnements. Il s'agit de la projection de l'amplitude du mouvement par rapport aux axes X et Y. Le Pas de changement représente l'incrémentation temporelle, autrement dit à quel rythme nous allons calculer la nouvelle position. La rotation initiale est stockée dans la variable Rotdepart. La dernière variable Temps est consacrée à gérer le temps de fonctionnement, elle est intimement liée au Pas.

La méthode initialisations sert à initialiser toutes ces variables. Pour la Periode et le Pas vous pouvez essayer différentes valeurs pour voir les effets. Pour trouver la rotation de départ on utilise la fonction llGetRot que nous avons déjà vu pour le script de la porte. Vous savez qu'on obtient un quaternion, pour nous simplifier la vie nous transformons cette valeur en Euler avec la fonction llRot2Euler. J'ai pris une demie Amplitude de 40° que je transforme en radians grâce à la constante DEG_TO_RAD. Ensuite nous déterminons les composantes de l'amplitude sur les axes X et Y avec les fonctions cosinus et sinus.

L' organisation générale du script est très simple avec deux états : le classique default qui contient seulement l'événement touch_start dans l'attente qu'un avatar touche la balançoire, ce qui a pour effet de basculer dans l'état marche. Dans cet état l'événement state_entry lance l'initialisation et le timer avec le Pas.

Au niveau de l'événement timer nous trouvons l'animation proprement dite. On commence par incrémenter le Temps de la valeur du Pas. Ensuite nous calculons le nouvel angle par rapport aux axes X et Y. L'amplitude est simplement multipliée par une fonction sinusoïdale du temps. Les non matheux peuvent sauter ces lignes ! Ensuite on calcule la rotation et on l'applique avec la fonction llSetRot que vous connaissez déjà.

Si la balançoire est touchée lorsqu'elle est en fonctionnement c'est l'événement touch_start de l'état marche qui est déclenché. Il suffit alors de ramener la balançoire à sa rotation initiale et à faire un reset du script.

 

lien permanent

Tutorial 8 Animation (2/2)  posté le mercredi 27 juin 2007 20:50

 

Je tiens à rappeler que les scripts que je propose dans ces tutoriaux ont une vocation essentiellement didactique. Le but est de présenter chaque fois des éléments nouveaux tout en revoyant certaines choses déjà rencontrées dans les tutos précédents. Ces scripts ne sont pas forcément complets et sans bugs, parfois il existe d'autres manières de faire plus performantes mais moins pédagogiques. Je livre donc ces codes sans aucune garantie si ce n'est celle d'apprendre un peu à programmer avec LSL...

Continuons notre animation des avatars avec cette fois un Danceball. Au niveau du fonctionnement envisageons du classique : une boule avec un texte flottant "Danser", avec un clic droit le menu propose "Danser" à la place de "Sit", le danceball contient plusieurs animations et le choix est aléatoire, au clic sur "Danser" une première danse démarre et le DanceBall disparaît ainsi que le texte flottant. Au bout d'un certain délai l'animation change, et ainsi de suite jusqu'à ce qu'on clique sur "Se lever", à ce moment là l'animation s'arrête et le Danceball réapparaît avec son texte flottant. Vous avez juste à créer une boule de votre couleur favorite et de poser dedans le code suivant :

 

// Animation en cours
string Animation;
// Nombre total de danses
integer Total;

initialisations()
{
   // Danceball visible au depart
   llSetAlpha(TRUE, ALL_SIDES);
   // Texte au-dessus du Danceball
   llSetText("Danser", <1.0,1.0,1.0>, 1.0);
   // Positionnement de l'animation
   llSitTarget(<0,0,-.3>, ZERO_ROTATION);
   // Nombre de danses
   Total = llGetInventoryNumber(INVENTORY_ANIMATION);
   if (Total == 0)
   {
      llWhisper(0, "Erreur: Pas d'animation...");
      return;
   }
   // Changement du menu
   llSetSitText("Danser");
}

animer(string anim)
{
   // Arret de l'animation precedente
   llStopAnimation(anim);
   // Animation aleatoire nouvelle
   string TempAnim = Animation;
   do {
      Animation = llGetInventoryName(INVENTORY_ANIMATION, (integer)llFrand(Total - 1));
   } while (Animation == TempAnim);
   // Animation en marche
   llStartAnimation(Animation);
}

default
{
   state_entry()
   {
      initialisations();
   }

   on_rez(integer start_param)
   {
      initialisations();
   }

   changed(integer change)
   {
      // Test de changement dans les liaisons
      if (change & CHANGED_LINK)
      {
         // Determination de la clef de l'avatar
         key AgentKey = llAvatarOnSitTarget();
         // Un avatar present ?
         if (AgentKey)
         {
            // Permission d'animation
            llRequestPermissions(AgentKey, PERMISSION_TRIGGER_ANIMATION);
            // Demarrage du timer
            llSetTimerEvent(60.0);
            // Effacement du Danceball
            llSetAlpha(FALSE, ALL_SIDES);
            // Effacement du texte flottant
            llSetText("", <0,0,0>, 1.0);
         }
         else
         {
            // Arret de l'animation
            llStopAnimation(Animation);
            // Reinitialisation du script pour le prochain avatar
            llResetScript();
         }
      }
   }

   timer()
   {
         // Changement de l'animation
         animer(Animation);
   }

   run_time_permissions(integer permissions)
   {
      if(permissions == PERMISSION_TRIGGER_ANIMATION && Total > 0)
         // Desactivation de l'animation par defaut "sit" et depart premiere animation
         animer("sit");
   }
}

Il faut aussi poser des animations de danse dans votre boule. Au final votre Danceball contient donc un script et des animations. Comme à notre habitude nous allons analyser ce code dans le détail.

Deux variables globales permettent de mémoriser l'animation en cours et le nombre total d'animations contenues dans le Danceball. A la phase d'initialisation le Danceball est rendu visible avec la fonction llSetAlpha qui possède deux paramètres : le premier est la valeur alpha, c'est-à-dire le degré de transparence souhaité (à 0 c'est complètement transparent et à 1 totalement opaque, entre les deux la transparence est plus ou moins importante), comme nous voulons parfaitement voir le Danceball il faut utiliser la valeur 1. Pourquoi avoir utilisé TRUE ? Vous vous souvenez sans doute que TRUE correspond à 1 et FALSE à 0. Le fait de mettre TRUE apporte plus de lisibilité au code, enfin c'est mon point de vue ! Le deuxième paramètre correspond aux faces (side) que vous désirez affecter avec votre valeur alpha. La constante ALL_SIDES signifie "toutes les faces", pour notre sphère de toutes façon il n'y a qu'une seule face et nous aurions tout aussi bien pu mettre la valeur 0. Mais si vous avez par exemple un cube alors vous avez 6 faces et la constante devient bien pratique pour affecter toutes les faces d'un coup.

Le texte flottante st créé avec la fonction llSetText. Le premier paramètre est le texte à afficher, le second sa couleur et le troisième sa transparence (alpha). Le vecteur <1.0,1.0,1.0> correspond aux valeurs maximales des primaires rouge, vert et bleu, donc à la couleur blanche. Quant à la transparence la valeur 1 signifie opaque comme nous l'avons déjà vu ci-dessus.

Nous avons déjà vu la fonction au précédent tuto, je passe donc à l'instruction suivante. Elle va me permettre d'introduire la notion d'inventaire (inventory). Jetez un coup d'oeil à cette page :

 

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

 

Vous pouvez y lire qu'il existe deux sortes d'inventaires; celui de l'avatar que vous connaissez bien dans lequel vous stockez vos habits, animations et autres merveilles, et celui des objets que vous connaissez moins. Vous pouvez mettre ce que vous voulez dans un objet, nous avons déjà vu que nous pouvons y mettre des scripts, des sons et des animations. Mais vous pouvez aussi y mettre des textures, des landmarks, des notecards... Il existe un certain nombre de fonctions pour gérer tout ce bazar. Ce qui nous intéresse pour le moment est le nombre d'animations contenues dans notre Danceball. C'est la fonction llGetInventoryNumber qui va nous le dire. Il suffit de lui passer en paramètre le type de contenu dont nous voulons connaître la quantité. Vous avez sur la page du WIKI toutes les constantes qui peuvent être utilisées. Dans notre cas il nous faut INVENTORY_ANIMATION puisque nous voulons connaître le nombre d'animations. Cette valeur est stockée dans la variable globale Total pour être utilisée ultérieurement dans le script.

Ensuite j'ai prévu un petit test pour vérifier que notre Danceball contient effectivement des animations. Si le Total est égal à 0 alors on envoie une message au niveau du Chat. Remarquez que l'utilisation de la fonction llWhisper à la place de llSay permet de limiter la portée du message à 10 mètres au lieu des classiques 20 mètres de llSay. Ensuite le return permet de sortir de l'initialisation sans accéder à l'instruction suivante. Par contre si le test est positif on change l'indication du menu comme nous l'avons fait au tuto précédent.

Arrivés à ce stade il ne se passe plus rien tant qu'un avatar n'a pas la bonne idée de s'asseoir sur le Danceball. A ce moment là l'événement changed est déclenché. Je passe rapidement sur les premières instructions qui sont identiques à celle du précédent tuto. On teste si une nouvelle liaison est présente, si c'est un avatar, et si c'est le cas on demande la permission de l'animer. On sait que cela déclenche l'événement run_time_permissions, au niveau de cet événement on vérifie la permission et aussi que le total des animation est bien supérieur à 0, donc que nous allons pouvoir lancer une animation. A ce moment là nous appelons la méthode animer avec comme paramètre l'animation par défaut sit :

 

animer(string anim)
{
   // Arret de l'animation precedente
   llStopAnimation(anim);
   // Animation aleatoire nouvelle
   string TempAnim = Animation;
   do {
      Animation = llGetInventoryName(INVENTORY_ANIMATION, (integer)llFrand(Total - 1));
   } while (Animation == TempAnim);
   // Animation en marche
   llStartAnimation(Animation);
}

 

On commence par arrêter l'animation passée en paramètre, dans notre cas il s'agit de sit, mais au prochain appel de la méthode ce sera la première animation lancée, et ainsi de suite... l'instruction suivante crée une variable de type string pour mémoriser l'animation actuelle, dans notre premier passage celle-ci est vide mais pour les passages suivant elle contiendra l'animation en cours. Ensuite nous avons un nouvel élément avec le mot clef do. Il s'agit d'une boucle, on dit de faire (do) une chose tant qu'une condition est satisfaite (while). Que faisons-nous dans cette boucle ? Avec la fonction llGetInventoryName nous allons chercher une animation dans l'inventaire du Danceball. Cette fonction attend comme premier paramètre le type d'élément désiré, nous retrouvons notre constante déjà vue plus haut, et en deuxième paramètre l'index dans la collection des éléments concernés. Imaginons que nous avons mis 6 animations, elles sont indexées de 0 à 5. c'est cette valeur qu'attend la fonction. ici nous utilisons la fonction llFrand que nous connaissons déjà pour générer une valeur aléatoire dans la gamme des index possible en nous référant au nombre total d'animations. Mais à quoi sert donc la boucle ? Et bien le test de la boucle est constitué par la vérification que l'animation choisie au hasard n'est pas celle déjà en cours. Autrement dit on ne veut pas avoir deux fois de suite la même danse. A la sortie on lance la nouvelle animation sélectionnée.

Revenons maintenant à l'événement changed que nous avons un peu abandonné. Nous voyons qu'après la demande de permission nous lançons un timer réglé à 60 secondes. Délai choisi entre les différentes danses. Au niveau de l'événement du timer vous constatez qu'on se contente d'appeler notre méthode animer avec l'animation en cours en paramètres. Nous comprenons maintenant pourquoi. Après l'initialisation du timer on efface la Danceball avec la fonction llSetAlpha en mettant cette fois son premier paramètre à 0 (FALSE). Il ne reste plus après qu'à effacer le texte flottant avec la même fonction qui nous a servi pour l'afficher llSetText mais cette fois en passant une chaîne de caractères vide et la couleur noire <0,0,0>.

J'espère que ce tutorial vous donnera envie de vous lancer dans la création. N'hésitez pas à me faire part de vos réalisations.

 

 

lien permanent

Tutorial 7 Animation (1/2)  posté le samedi 23 juin 2007 11:52

 

Jusque là nous ne nous sommes intéressés qu'aux objets, voyons un peu ce que ça donne du côté des avatars. S'il est relativement facile de faire bouger des objets, de les redimensionner, de changer leur couleur et leur texture il n'en est pas de même pour les avatars, heureusement ! Un avatar dépend de son propriétaire et nous ne pouvons intervenir sur lui qu'avec son accord (sauf rare exception dont je ne parlerai pas). Commençons par quelques précisions syntaxiques. Second Life est constitué de simulateurs (simulator, on dit souvent sim ou region) dont chacun est chargé de gérer un espace de 256 m². Ces simulateurs sont mis en oeuvres par des PC, chacun chargé de gérer un certain nombre de simulateurs. Une page du wiki vous donne plus de renseignements sur les simulateurs :

 

http://lslwiki.net/lslwiki/wakka.php?wakka=simulator

 

Un utilisateur de SL, comme vous et moi est constitué d'un agent et d'un avatar. Un agent est géré directement par le simulateur comme une présence. Un avatar est l'aspect visuel d'un agent : un corps avec toutes ses caractéristiques morphologiques. Un avatar peut porter des habits, avoir des attachements et subit les lois de la physique. Dans le reste de ce tutorial je ne vous parlerai que d'avatar. Pour animer un avatar il faut utiliser des animations. Une animation est une petite séance de cinéma pour avatar... Il en existe un certain nombre incluses dans SL. Vous les avez toutes listées ici :

 

http://lslwiki.net/lslwiki/wakka.php?wakka=animation

 

Mais vous pouvez en trouver bien d'autres dans les boutiques free. Vous pouvez aussi en créer avec des logiciels comme Poser au format BVH. Pour ce tutorial je vous propose d'utiliser une animation intégrée : sleep. Comme son nom l'indique c'est pour faire dormir un avatar ! Le contexte est simple : un lit, un avatar, un clic droit sur le lit, à la place du classique "sit" apparaît "dormir" et lorsque l'avatar clique sur celui-ci il va gentiment se coucher sur le lit. Voici le code correspondant que je vais vous commenter :

 

// Animation
string Animation;

initialisations()
{
   // Animation
   Animation = "sleep";
   // Changement du menu
   llSetSitText("Dormir");
   // Positionnement de l'animation
   llSitTarget(<0,0,1>, ZERO_ROTATION);
}

default
{
   state_entry()
   {
      initialisations();
   }

   on_rez(integer start_param)
   {
      initialisations();
   }

   changed(integer change)
   {
      // Test de changement dans les liaisons
      if (change & CHANGED_LINK)
      {
         // Determination de la clef de l'avatar
         key AgentKey = llAvatarOnSitTarget();
         // Un avatar present ?
         if (AgentKey)
         {
            // Permission d'animation
            llRequestPermissions(AgentKey, PERMISSION_TRIGGER_ANIMATION);
         }
         else
         {
            // Arret de l'animation
            llStopAnimation(Animation);
            // Reinitialisation du script pour le prochain avatar
            llResetScript();
         }
      }
   }

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

 

Pour un peu vous reposer du tuto précédent j'ai fait tout simple cette fois. Une seule variable globale Animation chargée de mémoriser le nom de l'animation. Pour mon exemple j'ai choisi sleep mais vous pouvez évidemment prendre n'importe laquelle, enfin presque mais j'y reviendrai. Au niveau de l'initialisation, après avoir affecté la variable Animation, je change le texte du menu du clic droit. Par défaut on voit apparaître sit, ici je le remplace avec "dormir". C'est la fonction llSetSitText qui nous permet de faire ça. Attention vous n'avez droit qu'à 9 caractères ! Le dernier élément de l'initialisation est assuré par la fonction llSitTarget. Cette fonction a une double utilité. D'abord elle permet de définir l'emplacement exact de l'animation par rapport à l'objet (un vertor d'offset et une rotation). Ensuite elle permet d'utiliser la fonction llAvatarOnSitTarget qui détermine si un avatar vient de s'asseoir et nous renvoie sa clef (Key). En plus un événement changed est renvoyé lorsqu'un avatar s'assoit. Autrement dit à l'issue de cette initialisation on attend l'événement changed... Cet événement est important, regardons le de plus près :

 

http://lslwiki.net/lslwiki/wakka.php?wakka=changed

 

Vous constatez qu'il survient dès qu'il se passe quelque chose au niveau de l'objet : inventaire, couleur, forme, taille, texture, liaisons, possession, region, téléportation... Le seul paramètre de l'événement est un integer, autrement dit une variable de 32 bits. A chacun de ces bits correspond une valeur vraie ou fausse. Ce qui permet de stocker 32 valeurs booléennes. Pour extraire une de ces valeurs il faut utiliser un "et" logique. Considérons le CHANGED_LINK, qui nous concerne pour notre script puisque lorsqu'un avatar s'assoit sur un objet il se retrouvé lié à celui-ci en dernière position de la hiérarchie. Dans le tableau du WIKI nous voyons que cette constante a pour valeur 0x20. Cette valeur peut vous paraître étrange si vous n'êtes pas habitué à d'autre système de numération que la décimale ! Elle est en hexadécimal. Pour ceux qui ignorent de quoi il s'agit je vous renvoie à cette page :

 

http://fr.wikipedia.org/wiki/Syst%C3%A8me_hexad%C3%A9cimal

 

La valeur hexadécimale 20 (le "0x" placé devant sert juste à signifier qu'il s'agit d'un hexadécimal) correspond donc à 32 en décimal et à 10000 en binaire. Donc lorsqu'il survient un changement dans les liaisons des prims d'un objet l'événement changed renvoie la valeur binaire 100000. Si nous appliquons un "ET" logique entre la valeur du paramètre renvoyé par l'événement et la valeur 100000 (on appelle cela un masque en programmation) le résultat sera "VRAI". Voilà comment nous détectons la présence d'un avatar. Une fois que nous l'avons détecté nous devons savoir de qui il s'agit, pour cela la fonction llAvatarOnSitTarget nous donne sa clef (Key). Ensuite il faut quand même effectuer un test pour savoir si le lien supplémentaire est vraiment un avatar et pas un simple prim ajouté ! Si nous avons une valeur correcte de clef alors c'est bon, c'est bien un avatar. Nous devons alors lui demander la permission de lui appliquer une animation avec la fonction llRequestPermissions. Regardez cette page :

 

http://lslwiki.net/lslwiki/wakka.php?wakka=llRequestPermissions

 

Vous constatez qu'on l'interroge pour pas mal de choses ! Ce qui nous intéresse là est représenté par la constante PERMISSION_TRIGGER_ANIMATION qui est aussi un masque de valeur 16 en décimal, donc 1000 en binaire. On sait si l'avatar est d'accord par l'intermédiaire de l'événement run_time_permissions dont le paramètre unique détermine le type d'autorisation. Vous en avez la liste ici :

 

http://lslwiki.net/lslwiki/wakka.php?wakka=run_time_permissions

 

Vous constatez qu'on retrouve notre PERMISSION_TRIGGER_ANIMATION avec la même valeur. Dans l'interception de l'événement nous faisons un test pour savoir si nous recevons la bonne valeur de paramètre. Ensuite il faut désactiver l'animation par défaut sit avec la fonction llStopAnimation puis lancer notre animation avec la fonction llStartAnimation.

Le dernier point à prendre en compte c'est que nous recevons l'événement changed aussi lorsque l'avatar se lève. A ce moment là il faut stopper notre animation et faire un Reset du script.

 

lien permanent



 

fermer la barre

Vous devez être connecté pour écrire un message à lsl

Vous devez être connecté pour ajouter lsl à vos amis

 
Créer un blog