Articulations

Répondre
Partager Rechercher
En continuité de mon système pour les portes à charnière j'ai mis au point un pack plus complet pouvant traiter une succession d'articulations, comme je l'ai montré dans les vidéos sur ce fil : https://forums.jeuxonline.info/showthread.php?t=1193946&page=2.

Le principe est basé sur la mise en place d'axes comme repères de rotation, avec un maximum de 6 axes (pourquoi 6 ? J'avais fait une liste de 6 couleurs équilibrées alors je me suis limité à 6 axes mais le système pourrait en supporter plus...)

Les axes doivent être parallèles. Ils sont aussi hiérarchisés. Quand on pose le premier axe il est rouge et s'appelle axe_0, le second est jaune et s'appelle axe_1 et ainsi de suite jusqu'au sixième qui est bleu et s'appelle axe_5.

Un axe est simplement un cylindre suffisamment aminci dans lequel on met ce script :

Cliquez ce bouton ou survolez le contenu pour afficher le spoiler
Code PHP:

////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                            //
//                                  Articulation Axe V 1.00                                     //
//                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////
//                          Copyright (c) 2012 by Bestmomo Lagan                              //
////////////////////////////////////////////////////////////////////////////////////////////////
//   This program is free software: you can redistribute it and/or modify                     //
//    it under the terms of the GNU General Public License as published by                    //
//    the Free Software Foundation, either version 3 of the License, or                       //
//    (at your option) any later version.                                                     //
//                                                                                            //
//    Articulations is distributed WITHOUT ANY WARRANTY;                                      //
//    See the GNU General Public License for more details.                                    //
//                                                                                            //
//    To get a copy of the GNU General Public License, see <http://www.gnu.org/licenses/>.    //
////////////////////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------
//        Paramètres
// -----------------------------------------------

integer CANAL_AXE     = -2253600;
integer CANAL_SETUP   = -2253610;
list     
COULEURS      = [<1,1,0>,<0,1,0>,<0,1,1>,<0,0,1>,<1,0,1>];

// -----------------------------------------------
//        Variables de travail
// -----------------------------------------------
list    l_noms;
integer i_id;

// -----------------------------------------------
//        Canal aléatoire
// -----------------------------------------------
integer genCanal() {return ~(integer)llFrand((float)DEBUG_CHANNEL);}

// -----------------------------------------------
//        Paramètres primitive
// -----------------------------------------------
string get_nom() {return llList2String(llGetPrimitiveParams([PRIM_NAME]), 0);}
set_nom(string nom) {llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_NAMEnom]);}
set_couleur(vector couleur) {llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_COLORALL_SIDEScouleur1]);}
set_texte(string texte) {llSetText(texte, <1,1,1>, 1);}

// -----------------------------------------------
//        Test initial
// -----------------------------------------------
test_initial() {
    
// Initialisations
    
l_noms = [];
    
set_texte("");
    
// On écoute sur canal des axes
    
llListen(CANAL_AXE""NULL_KEY"");
    
// Ecoute setup
    
llListen(CANAL_SETUP 1""NULL_KEY"");
    
// Le test est émis
    
llWhisper(CANAL_AXE"TEST");
    
// Délai d'attente de la réponse
    
llSetTimerEvent(2.0);
}

// -----------------------------------------------
//        Etat initial de création des axes
// -----------------------------------------------
default
{
    
state_entry() {
        
test_initial();
    }

    
on_rez(integer start_param){
        
test_initial();
    }

    
listen(integer channelstring namekey idstring message) {
        if(
channel == CANAL_AXE) {
            list 
llParseString2List(message, [":"], []);
            
// Retour de demande de nom
            
if(llList2String(l0) == "TEST_BACK"l_noms += llList2String(l1);
            
// Réception de demande de nom
            
else if(llList2String(l0) == "TEST"llWhisper(CANAL_AXE"TEST_BACK:" get_nom());
        }
        else if(
channel == CANAL_SETUP && message == "GO")
            
state setup;
    }

    
timer() {
        
llSetTimerEvent(.0);
        
// Réponses reçues
        
if(llGetListLength(l_noms)) {
            
// On passe en revue les axes présents pour connaitre l'index suivant
            
list l;
            
integer n llGetListLength(l_noms);
            
// Test de limite
            
if(5) {
                
llOwnerSay("Limite dépassée ! Pas plus de 6 axes !");
                
llDie();
            }
            else {
                while(
n--) {
                    
string nom llList2String(l_nomsn);
                    
+= (integer)llGetSubString(nom, -1, -1);
                }
                
i_id = (integer)llListStatistics(LIST_STAT_MAXl) + 1;
                
set_nom("axe_" + (string)i_id);
                
set_texte(get_nom());
                
set_couleur(llList2Vector(COULEURSi_id 1));
                
// On écoute sur canal de setup
                
llListen(CANAL_SETUP 1""NULL_KEY"");
            }
        }
        
// Pas de réponse reçue : premier axe
        
else {
            
set_nom("axe_0");
            
set_texte("axe_0");
            
i_id 0;
            
set_couleur(<1,0,0>);
            
// On écoute sur canal de setup
            
llListen(CANAL_SETUP""NULL_KEY"");
        }
    }
}

// -----------------------------------------------
//        Etat de setup
// -----------------------------------------------
state setup
{
    
state_entry() {
        
// Ecoute setup
        
llListen(CANAL_SETUP 1""NULL_KEY"");
    }
    
on_rez(integer start_param){
        
llResetScript();
    }

    
listen(integer channelstring namekey idstring message) {
        if(
message == "DIE"llDie();
        list 
llParseString2List(message, ["@"], []);
        
// Est-ce que c'est pour moi ?
        
if((integer)llList2String(l1) == i_id) {
            
// Réponse à demande de position initiale
            
if(llList2String(l0) == "ASK")
                
llSay(CANAL_SETUP"SET@" + (string)llGetPos() + "@" + (string)(llGetPos() + <.0,.0,1.0> * llGetRot()));
            
// Ordre de mouvement
            
else if(llList2String(l0) == "MOVE")
                
llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_POSITION, (vector)llList2String(l2)]);
        }
    }



La première fois que vous créez un axe mettez le dans votre inventaire, en effet il est détruit à l'issue du setup. Pour avoir plusieurs axes, soit vous faites des copies, soit vous en posez d'autres à partir de votre inventaire. Seule contrainte : attendre au moins 2 secondes entre chaque génération pour ne pas avoir d'axes identiques.

Principe du setup :

Vous créez votre objet avec toutes les primitives liées en les positionnant correctement dans un état initial. Ensuite vous positionnez les axes là où vous voulez des articulations en partant du principe :

un axe = une primitive

Lorsque vous avez un autre axe il est fonctionnellement lié à la primitive de l'axe précédent. Vous avez donc la succession :

axe_0 -> primitive -> axe_1 -> primitive -> axe_2..... et ainsi de suite

Lorsque tout est en place (objet et tous les axes nécessaires) vous mettez le script de setup dans la racine :

Cliquez ce bouton ou survolez le contenu pour afficher le spoiler
Code PHP:

////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                            //
//                                 Articulation Setup V 1.02                                    //
//                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////
//                          Copyright (c) 2012 by Bestmomo Lagan                              //
////////////////////////////////////////////////////////////////////////////////////////////////
//   This program is free software: you can redistribute it and/or modify                     //
//    it under the terms of the GNU General Public License as published by                    //
//    the Free Software Foundation, either version 3 of the License, or                       //
//    (at your option) any later version.                                                     //
//                                                                                            //
//    Articulations is distributed WITHOUT ANY WARRANTY;                                      //
//    See the GNU General Public License for more details.                                    //
//                                                                                            //
//    To get a copy of the GNU General Public License, see <http://www.gnu.org/licenses/>.    //
////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////
//                           Parameters that you can change                                   //
////////////////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////////////////////
//                Dont change code below unless you know what you do                          //
////////////////////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------
//        Variables de travail
// -----------------------------------------------
integer     i_canal_menu;
integer     i_step;
float       f_angle;
integer     i_menu;

// Valeurs d'état intermédiaire de la position de l'axe
list        l_v_centre_state_int;

// Axe
vector      v_axe;

// Links primitives avec déjà un setup
list        l_link_setup;

// Id de ce setp
string      s_setup "0";

// -----------------------------------------------
//        Variables de paramétrage
// -----------------------------------------------
// Numéro de liaison de la prim
list        l_link;

// Position des axes pour les deux états
list        l_v_centre_state_1;
list        
l_v_centre_state_2;

// Rotation des prims pour les deux états
list        l_r_rot_state_1;
list        
l_r_rot_state_2;

// Position des prims pour les deux états
list        l_v_pos_state_1;
list        
l_v_pos_state_2;

// Rotation des vecteurs tournants
list        l_vec_rot = [ZERO_ROTATION,ZERO_ROTATION,ZERO_ROTATION,ZERO_ROTATION,ZERO_ROTATION,ZERO_ROTATION];

// -----------------------------------------------
//        Paramètres à ne pas toucher
// -----------------------------------------------
integer    CANAL_SETUP     = -2253610;

// -----------------------------------------------
//        Canal aléatoire
// -----------------------------------------------
integer genCanal() {
    return ~(integer)
llFrand((float)DEBUG_CHANNEL);
}
// -----------------------------------------------
//        Gestion des menus
// -----------------------------------------------
// Envoi du menu à l'owner
set_menu(string texte, list menu) {
    
llDialog(llGetOwner(), textemenui_canal_menu);
}
// Menu de sélection des liaisons
menu_liaisons() {
    list 
= ["Next"];
    if(
i_step= ["Back"] + l;
    
set_menu("\nClick the primitive linked to axe_" + (string)i_step "\n(click again to unlink) \nand click on \"Next\" when done"l);
}
// Menu de réglage rotation
menu_setup() {
    
set_menu("\nAdjust prim link_axe_" + (string)i_step " \nand click on another one when it's done\nor \"End\" if all prims are adjusted"
        
, ["-1","End","+1","-5","< >","+5","-20","< >","+20","-90","< >","+90"]);
}

// -----------------------------------------------
//        Passage de position globale <-> locale
// -----------------------------------------------
vector global_to_local(vector position) {
    return (
position llGetRootPosition()) / llGetRootRotation();
}
vector local_to_global(vector position) {
    return 
llGetRootPosition() + position llGetRootRotation();
}

// -----------------------------------------------
//        Passage de rotation globale <-> locale
// -----------------------------------------------
rotation rot_to_local(rotation rot) {
    return 
rot llGetRootRotation();
}
rotation rot_to_global(rotation rot) {
    return 
rot llGetRootRotation();
}

// -----------------------------------------------
//        Paramètres primitive
// -----------------------------------------------
string get_texte(integer id) {
    return 
llList2String(llGetLinkPrimitiveParams(id, [PRIM_TEXT]), 0);
}
set_texte(integer idvector col) {
    
llSetLinkPrimitiveParamsFast(id, [PRIM_TEXT"Link to axe_" + (string)i_stepcol1]);
}
unset_texte(integer id) {
    
llSetLinkPrimitiveParamsFast(id, [PRIM_TEXT"", <0,0,0>, 0]);
}
vector get_pos(integer id) {
    return 
llList2Vector(llGetLinkPrimitiveParams(id, [PRIM_POS_LOCAL]), 0);
}
rotation get_rot(integer id) {
    return 
llList2Rot(llGetLinkPrimitiveParams(id, [PRIM_ROT_LOCAL]), 0);
}

// -----------------------------------------------
//        Position instantanée
// -----------------------------------------------
set_pos_inst() {
    
integer n llGetListLength(l_v_centre_state_1);
    
integer i;
    
// Initialisations
    
l_v_pos_state_2 = [];
    
l_r_rot_state_2 = [];
    
l_v_centre_state_2 = [];
    
// Boucle
    
for(; n; ++i) {
        
integer id llList2Integer(l_linki);
        
l_v_pos_state_2 += get_pos(id);
        
l_r_rot_state_2 += get_rot(id);
        
l_v_centre_state_2 += llList2Vector(l_v_centre_state_inti);
    }
    
f_angle 0;
}

// -----------------------------------------------
//        Vérification des setup déjà présents
// -----------------------------------------------
get_infos() {
    
// Recherche des primitives avec déjà un setup
    
integer n llGetNumberOfPrims();
    list 
l_id;
    
integer i;
    for(
2<= n; ++i) {
        
string s get_texte(i);
        if(
!= "") {
            if(
llGetSubString(s00) == "!") {
                
l_link_setup += i;
                
l_id += (integer)llGetSubString(s11);
            }
        }
    }
    
// Détermination de l'id de ce setup
    
if(llGetListLength(l_id)) s_setup = (string)((integer)llListStatistics(LIST_STAT_MAXl_id) + 1);
}

// -----------------------------------------------
//        Sauvegardes informations
// -----------------------------------------------
save_infos() {
    
integer n llGetListLength(l_link);
    while(
n--) {
        
string s "!" s_setup + (string)n
            
"@" compact_info(llList2Vector(l_v_centre_state_1n))
            + 
"@" compact_info(llList2Vector(l_v_centre_state_2n))
            + 
"@" compact_info(llRot2Euler(llList2Rot(l_r_rot_state_1n)) * RAD_TO_DEG)
            + 
"@" compact_info(llRot2Euler(llList2Rot(l_r_rot_state_2n)) * RAD_TO_DEG)
            + 
"@" compact_info(llList2Vector(l_v_pos_state_1n))
            + 
"@" compact_info(llList2Vector(l_v_pos_state_2n))
            + 
"@" compact_info(llRot2Euler(llList2Rot(l_vec_rotn)) * RAD_TO_DEG);
        
llSetLinkPrimitiveParamsFast(llList2Integer(l_linkn), [PRIM_TEXTsZERO_VECTOR0]);
    }
}
string compact_info(vector v) {
    return 
get_part(v.x) + "," get_part(v.y) + "," get_part(v.z);
}
string get_part(float f) {
    if(
== .0) return "0";
    else return 
llGetSubString((string)f05);
}

// -----------------------------------------------
//        Récupération des infos des axes
// -----------------------------------------------
default
{
    
state_entry() {
        
llOwnerSay(llGetScriptName() + " ready.");
        
llSetText("Setup in progess...", <1,1,1>, 1);
        
// Récupération infos setup antérieurs éventuels
        
get_infos();
        
// Ecoute pour les axes
        
llListen(CANAL_SETUP""NULL_KEY"");
        
// Message de début de setup
        
llSay(CANAL_SETUP 1"GO");
        
// Petit délai
        
llSleep(2.0);
        
// Message au premier axe
        
llSay(CANAL_SETUP 1"ASK@0");
        
llSetTimerEvent(2.0);
    }

    
listen(integer channelstring namekey idstring message) {
        
// Réception messages des axes
        
list llParseString2List(message, ["@"], []);
        
// Récupération des données de l'axe
        
if(llList2String(l0) == "SET") {
            
vector v_centre_global = (vector)llList2String(l1);
            
rotation r_global = (rotation)llList2String(l2);
            
vector v_centre_local global_to_local(v_centre_global);
            
rotation r_local rot_to_local(r_global);
            
l_v_centre_state_1 += v_centre_local;
            
l_v_centre_state_int += v_centre_local;
            if(!
i_stepv_axe llVecNorm(v_centre_local + <.0,.0,1.0> * r_local  v_centre_local);
            
// Message axe suivant
            
llSay(CANAL_SETUP 1"ASK@" + (string)(++i_step));
            
llSetTimerEvent(2.0);
        }
    }

    
timer() {
        
llSetTimerEvent(.0);
        if(
i_step == 0llOwnerSay("I didn't find an axis !");
        else
            
state liaisons;
    }
}

// -----------------------------------------------
//        Définition des liaisons
// -----------------------------------------------
state liaisons
{
    
state_entry() {
        
// Message pour axe_0
        
i_step 0;
        
llOwnerSay("Click on the primitive linked to axe_0");
    }

    
touch_start(integer total_number) {
        
integer id llDetectedLinkNumber(0);
        
// On ne doit pas lier le root ni deux fois la même primitive !
        
if(id != && llListFindList(l_link, [id]) == -1) {
            
set_texte(id, <1,1,1>);
            
// Mémorisation des informations
            
l_link += id;
            
l_v_pos_state_1 += get_pos(id);
            
l_r_rot_state_1 += get_rot(id);
            
// Nouvelle liaison
            
if(++i_step llGetListLength(l_v_centre_state_1))
                
llOwnerSay("Click on the primitive linked to axe_" + (string)i_step);
            
// Fin des liaisons
            
else {
                
i_step 0;
                
state etats;
            }
        }
    }
}

// -----------------------------------------------
//        Réglage du deuxième état
// -----------------------------------------------
state etats
{
    
state_entry() {
        
// Canal pour le menu
        
i_canal_menu genCanal();
        
// Ecoute pour le menu
        
llListen(i_canal_menu""llGetOwner(), "");
        
// Message
        
llOwnerSay("Set all elements for state 1 and click on the primitive you want to adjust for state 2");
    }

    
touch_start(integer total_number) {
        
integer i_link llDetectedLinkNumber(0);
        
integer i llListFindList(l_link, [i_link]);
        
integer i_bis llListFindList(l_link_setup, [i_link]);
        if(~
&& i_bis == -1) {
            
i_step 0;
            
integer n llGetListLength(l_v_centre_state_1);
            for(; 
i_step n; ++i_stepset_texte(llList2Integer(l_linki_step), <1,1,1>);
            
i_step i;
            
set_texte(i_link, <1,0,0>);
            
set_pos_inst();
            if(!
i_menu) {
                
i_menu TRUE;
                
menu_setup();
            }
        }
    }

    
listen(integer channelstring namekey idstring message) {
        
// Réception messages des menus
        
if(channel == i_canal_menu) {
            
// Touche neutre
            
if(message == "< >" || message == " "menu_setup();
            
// Fin du réglage
            
else if(message == "End") {
                
// Mémorisation état 2
                
set_pos_inst();
                
// Effacement des textes flottants
                
unset_texte(1);
                
integer n llGetListLength(l_v_centre_state_1);
                while(
n--) unset_texte(llList2Integer(l_linkn));
                
// Destruction des axes
                
llSay(CANAL_SETUP 1"DIE");
                
// Enregistrement des informations
                
save_infos();
                
// Fin
                
llOwnerSay("Drop \"Articulation action\" script in object inventory");
                
llRemoveInventory(llGetScriptName());
            }
            
// Réglage en cours
            
else {
                
float f_valeur = (float)message;
                
f_angle += f_valeur;
                
integer n llGetListLength(l_v_centre_state_1);
                
integer i i_step;
                
// Mise en mouvement global
                
for(; n; ++i) {
                    
integer id_link llList2Integer(l_linki);
                    
rotation r llAxisAngle2Rot(v_axef_angle DEG_TO_RAD);
                    
vector v_tournant llList2Vector(l_v_pos_state_2i) - llList2Vector(l_v_centre_state_2i_step);
                    if(
== i_stepl_vec_rot llListReplaceList(l_vec_rot, [r], ii);
                    
llSetLinkPrimitiveParamsFast(id_link, [
                        
PRIM_POSITIONllList2Vector(l_v_centre_state_2i_step) + v_tournant r,
                        
PRIM_ROT_LOCALllList2Rot(l_r_rot_state_2i) * r]);
                    
// Encore un axe
                    
if(1) {
                        
v_tournant llList2Vector(l_v_centre_state_21) - llList2Vector(l_v_centre_state_2i_step);
                        
vector axe_pos llList2Vector(l_v_centre_state_2i_step) + v_tournant r;
                        
// Mémorisation de la position
                        
l_v_centre_state_int llListReplaceList(l_v_centre_state_int, [axe_pos], 11);
                        
// Ordre de mouvement à l'axe
                        
llSay(CANAL_SETUP 1"MOVE@" + (string)(1)
                            + 
"@" + (string)(local_to_global(axe_pos))
                            + 
"@" + (string)ZERO_ROTATION
                            
);
                    }
                }
                
menu_setup();
            }
        }
    }



Vous obtenez un message dans le Chat :

Click on the primitive linked to axe_0

Oui j'ai tout mis en anglais mais facile à comprendre . On vous demande de cliquer sur la primitive qui dépend de l'axe axe_0. Donc vous cliquez dessus et son texte flottant affiche Link to axe_0. On vous demande ensuite la même chose pour tous les axes. Quand c'est fait vous obtenez ce message :

Set all elements for state 1 and click on the primitive you want to adjust for state 2

Donc un petit rappel pour être sûr que tout est bien en place pour le premier état et là vous cliquez sur n'importe quelle primitive (parmi celles qui doivent bouger ), son texte flottant devient rouge et un menu vous invite à ajuster sa rotation. Vous faites pareil avec les autres primitives. Il n'y a pas d'ordre à respecter dans ce réglage.

Quand vous avez tout réglé vous cliquez sur "End" dans le menu. Le script de setup disparait, ainsi que les axes. Vous n'avez plus qu'à glisser le script d'action dans l'inventaire de la racine :

Cliquez ce bouton ou survolez le contenu pour afficher le spoiler
Code PHP:

////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                            //
//                                  Articulation Action V 1.04                                  //
//                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////
//                          Copyright (c) 2012 by Bestmomo Lagan                              //
////////////////////////////////////////////////////////////////////////////////////////////////
//   This program is free software: you can redistribute it and/or modify                     //
//    it under the terms of the GNU General Public License as published by                    //
//    the Free Software Foundation, either version 3 of the License, or                       //
//    (at your option) any later version.                                                     //
//                                                                                            //
//    Articulations is distributed WITHOUT ANY WARRANTY;                                      //
//    See the GNU General Public License for more details.                                    //
//                                                                                            //
//    To get a copy of the GNU General Public License, see <http://www.gnu.org/licenses/>.    //
////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////
//                           Parameters that you can change                                   //
////////////////////////////////////////////////////////////////////////////////////////////////

// Time
float       TIME            2;        // Transition time in seconds
integer     AUTO            FALSE;    // TRUE for loop mode
float       RETURNTIME      0;        // Time for auto return to first position (0 for no auto-return)
integer     API             FALSE;    // True for only API

// Access
string      ACCESS          "All";    // Access must be "All", "Group", "Owner" or "List"
list        ACCESSLIST      = [];       // Access names list if ACCESS is on "List"

// Sounds
string      SECONDSOUND     "none";   // Sound for second position ("none" if none)
string      FIRSTSOUND      "none";   // Sound for first position ("none" if none)

// Sensor
float       SENSOR_RANGE    0;        // Sensor range (0 for none), no touch action if sensor
float       SENSOR_DELAY    4;        // Sensor delay (no matter if no sensor)

// Messages
string      ACCESSMESSAGE   "Sorry but your are not allowed to command this object";
string      CLICKMESSAGE    "Come closer to command this object";

// API
integer     API_CLICK       111;      // Like a "click"
integer     API_AUTO_START  112;      // Start in "auto" mode
integer     API_AUTO_STOP   113;      // Stop in "auto" mode
integer     API_GO_POS_1    114;      // Go to first position
integer     API_GO_POS_2    115;      // Go to second  position
integer     API_GET_POS     116;      // To get position
integer     API_POS_ANSWER  117;      // POsition answer

////////////////////////////////////////////////////////////////////////////////////////////////
//                Dont change code below unless you know what you do                          //
////////////////////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------
//        Variables de paramétrage
// -----------------------------------------------
// Numéro de liaison de la prim
list        l_link;

// Position des axes pour les deux états
list        l_v_centre_state_1;
list        
l_v_centre_state_2;

// Rotation des prims pour les deux états
list        l_r_rot_state_1;
list        
l_r_rot_state_2;

// Position des prims pour les deux états
list        l_v_pos_state_1;
list        
l_v_pos_state_2;

// Rotation des vecteurs tournants
list        l_vec_rot = [ZERO_ROTATION,ZERO_ROTATION,ZERO_ROTATION,ZERO_ROTATION,ZERO_ROTATION,ZERO_ROTATION];

// -----------------------------------------------
//        Paramètres à ne pas toucher
// -----------------------------------------------
float      TEMPS_BASE    .04;

// -----------------------------------------------
//        Paramètres primitive
// -----------------------------------------------
string get_texte(integer id) {
    return 
llList2String(llGetLinkPrimitiveParams(id, [PRIM_TEXT]), 0);
}
vector get_pos(integer id) {
    return 
llList2Vector(llGetLinkPrimitiveParams(id, [PRIM_POS_LOCAL]), 0);
}

// -----------------------------------------------
//        Variables de travail
// -----------------------------------------------
integer     i_auto;

// -----------------------------------------------
//        Test d'accès
// -----------------------------------------------
integer test_access(key id) {
    if(
ACCESS == "List" && ~llListFindList(ACCESSLIST, [llKey2Name(id)])) return TRUE;
    else if(
ACCESS == "Owner" && llGetOwner() == id) return TRUE;
    else if(
ACCESS == "Group" && llSameGroup(id)) return TRUE;
    else if(
ACCESS == "All") return TRUE;
    else return 
FALSE;
}

// -----------------------------------------------
//        Interpolation
// -----------------------------------------------
rotation r_cos(rotation r0rotation r1float t){
    
float f = (llCos(PI)) / 2;
    
float f_ang llAngleBetween(r0r1);
    if(
f_ang PIf_ang -= TWO_PI;
    return 
r0 llAxisAngle2Rot(llRot2Axis(r1 r0) * r0f_ang f);
}

// -----------------------------------------------
//        Transition
// -----------------------------------------------
transition(integer i_back) {
    
float f_step 1.0 / (TIME TEMPS_BASE);
    
float step;
    while((
step += f_step) <= 1.0) {
        
integer n llGetListLength(l_link);
        
integer i;
        
rotation r_tot;
        
rotation r;
        
vector v_centre llList2Vector(l_v_centre_state_1 0);
        list 
l_params;
        for(; 
n; ++i) {
            if(
i_backr_cos(llList2Rot(l_vec_roti), ZERO_ROTATIONstep);
            else 
r_cos(ZERO_ROTATIONllList2Rot(l_vec_roti), step);
            
r_tot *= r;
            
vector v_tournant llList2Vector(l_v_pos_state_1i) - llList2Vector(l_v_centre_state_1 i);
            
vector pos v_centre v_tournant r_tot;
            if(
il_params += [PRIM_LINK_TARGETllList2Integer(l_linki)];
            
l_params += [PRIM_POSITIONposPRIM_ROT_LOCALllList2Rot(l_r_rot_state_1i) * r_tot];
            
// Encore un axe
            
if(1) {
                
v_tournant llList2Vector(l_v_centre_state_1 1) - llList2Vector(l_v_centre_state_1 i);
                
v_centre += v_tournant r_tot;
            }
        }
        
llSetLinkPrimitiveParamsFast(llList2Integer(l_link0), l_params);
        
llSleep(TEMPS_BASE);
    }
}

// -----------------------------------------------
//        Manoeuvre de l'objet
// -----------------------------------------------
// Test de première position
integer test_first() {
    return 
get_pos(llList2Integer(l_link0)) == llList2Vector(l_v_pos_state_10);
}

// Test de seconde position
integer test_second() {
    return 
get_pos(llList2Integer(l_link0)) == llList2Vector(l_v_pos_state_20);
}

// Manoeuvre sur clic
action_click() {
    
// Vers second
    
if(test_first()) {
        
go_second();
    }
    
// vers premier
    
else if(test_second()) {
        if(
RETURNTIME == .0go_first();
    }
    
// Cas où il y a eu une modification de build
    
else {
        
llSetText(""ZERO_VECTOR0);
        
llResetScript();
    }
}

// Passage en seconde position
go_second() {
    
transition(FALSE);
    
// Fixation de l'état
    
integer n llGetListLength(l_link);
    while(
n--) {
        
llSetLinkPrimitiveParamsFast(llList2Integer(l_linkn), [
            
PRIM_POSITIONllList2Vector(l_v_pos_state_2n),
            
PRIM_ROT_LOCALllList2Rot(l_r_rot_state_2n)]);
    }
    if(
SECONDSOUND != "none"llTriggerSound(SECONDSOUND1.0);
    else if(
RETURNTIME != .0 && SENSOR_RANGE == .0 && !AUTOllSetTimerEvent(RETURNTIME);
}

// Passage en première position
go_first() {
    
transition(TRUE);
    
// Fixation de l'état
    
integer n llGetListLength(l_link);
    while(
n--) {
        
llSetLinkPrimitiveParamsFast(llList2Integer(l_linkn), [
            
PRIM_POSITIONllList2Vector(l_v_pos_state_1n),
            
PRIM_ROT_LOCALllList2Rot(l_r_rot_state_1n)]);
    }
    if(
FIRSTSOUND != "none"llTriggerSound(FIRSTSOUND1.0);
}

// -----------------------------------------------
//        Détermination de l'index du script
// -----------------------------------------------
integer trouve_index() {
    list 
llParseString2List(llGetScriptName(), [" "], []);
    if(
llGetListLength(l) == 1) return 0;
    else return (integer)
llList2String(l1);
}

// -----------------------------------------------
//        Restitution informations
// -----------------------------------------------
integer get_infos() {
    
// Recherche des primitives avec texte
    
list l_textes;
    list 
l_id;
    
integer n llGetNumberOfPrims();
    
integer i;
    
string s_id = (string)trouve_index();
    for(
2<= n; ++i) {
        
string s get_texte(i);
        if(
!= "") {
            if(
llGetSubString(s01) == "!" s_id) {
                
l_textes += s;
                
l_id += i;
            }
        }
    }
    
// Traitement des informations
    
llGetListLength(l_textes);
    if(
n) {
        
n;
        while(
i--) {
            
l_link += 0;
            
l_v_centre_state_1 += 0;
            
l_v_centre_state_2 += 0;
            
l_r_rot_state_1 += 0;
            
l_r_rot_state_2 += 0;
            
l_v_pos_state_1 += 0;
            
l_v_pos_state_2 += 0;
        }
        while(
n--) {
            
string s llList2String(l_textesn);
            list 
llParseString2List(s, ["@"], []);
            
integer id = (integer)llGetSubString(s22);
            
l_link llListReplaceList(l_link, [llList2Integer(l_idn)], idid);
            
l_v_centre_state_1 llListReplaceList(l_v_centre_state_1, [get_vector(llList2String(l1))], idid);
            
l_v_centre_state_2 llListReplaceList(l_v_centre_state_2, [get_vector(llList2String(l2))], idid);
            
l_r_rot_state_1 llListReplaceList(l_r_rot_state_1, [get_rotation(llList2String(l3))], idid);
            
l_r_rot_state_2 llListReplaceList(l_r_rot_state_2, [get_rotation(llList2String(l4))], idid);
            
l_v_pos_state_1 llListReplaceList(l_v_pos_state_1, [get_vector(llList2String(l5))], idid);
            
l_v_pos_state_2 llListReplaceList(l_v_pos_state_2, [get_vector(llList2String(l6))], idid);
            
l_vec_rot llListReplaceList(l_vec_rot, [get_rotation(llList2String(l7))], idid);
        }
        return 
TRUE;
    }
    return 
FALSE;
}

rotation get_rotation(string s) {
    return 
llEuler2Rot((vector)("<" ">") * DEG_TO_RAD);
}
vector get_vector(string s) {
    return (
vector)("<" ">");
}

// -----------------------------------------------
//        Etat de fonctionnement
// -----------------------------------------------
default
{
    
state_entry() {
        
// Test présence d'infos
        
if(get_infos()) {
            
// Retour en première position après setup et après reset éventuel
            
integer n llGetListLength(l_link);
            while(
n--) {
                
llSetLinkPrimitiveParamsFast(llList2Integer(l_linkn), [
                    
PRIM_POSITIONllList2Vector(l_v_pos_state_1n),
                    
PRIM_ROT_LOCALllList2Rot(l_r_rot_state_1n)]);
            }
            
// Sensor éventuel
            
if(SENSOR_RANGE != .0 && !APIllSensorRepeat(""NULL_KEYAGENTSENSOR_RANGEPISENSOR_DELAY);
            
// Marche automatique
            
if(AUTO) {
                
i_auto TRUE;
                
llSetTimerEvent(.01);
            }
        }
    }

    
touch_start(integer total_number) {
        
// On vérifie que le clic se fait sur une prim qui doit bouger
        
if(~llListFindList(l_link, [llDetectedLinkNumber(0)]) && !API) {
            
key k llDetectedKey(0);
            if(
test_access(k)) {
                if(
SENSOR_RANGE == .0action_click();
                else if(
test_first()) llInstantMessage(kCLICKMESSAGE);
            }
            else 
llInstantMessage(kACCESSMESSAGE);
        }
    }

    
sensor(integer total_number) {
        
// Gestion si objet en première position
        
if(test_first()) {
            
// Test de personnes autorisées
            
while(total_number--) if(test_access(llDetectedKey(total_number))) {
                
go_second();
                return;
            }
            
// Si personne autorisée on met en seconde si première
            
else if(test_second()) go_first();
        }
    }

    
no_sensor() {
        
// Si personne on met en première
        
if(test_second()) go_first();
    }

    
link_message(integer sender_numberinteger numberstring messagekey id) {
        if(
number == API_CLICK && SENSOR_RANGE == .0action_click();
        else if(
number == API_GO_POS_1go_first();
        else if(
number == API_GO_POS_2go_second();
        else if(
number == API_GET_POS) {
            
llMessageLinked(LINK_THISAPI_POS_ANSWER, (string)test_second(), NULL_KEY);
        }
        else if(
AUTO) {
            if(
number == API_AUTO_START) {
                
i_auto TRUE;
                
llSetTimerEvent(.01);
            }
            else if(
number == API_AUTO_STOPi_auto FALSE;
        }
    }

    
timer() {
        
llSetTimerEvent(.0);
        if(
AUTO) {
            if(
i_auto) {
                if(
test_first()) go_second();
                else 
go_first();
                
llSetTimerEvent(.01);
            }
        }
        else 
go_first();
    }



Votre objet est opérationnel avec les paramètres par défaut !

Dans les paramètres situés en début du script d'action vous pouvez régler :


  • la durée de la rotation
  • le mode auto (va et vient ininterrompu)
  • la durée de retour si retour automatique
  • les droits d'accès
  • les sons éventuels dans les deux états
  • le sensor éventuel
  • des messages
  • une API pour une commande externe
Important : le nom du script d'action ne doit pas comporter d'espace. Par exemple "mon script" ne va pas alors que "mon_script" est correct.


Vous pouvez faire plusieurs setup dans un même objet, comme dans mon exemple de cube où j'ai fait 4 setup. Il suffit de recommencer tout le scénario et de mettre un nouveau script d'action à la fin avec le même nom.


Les paramètres étant mémorisés dans les textes flottants des primitives vous ne pourrez pas faire un nouveau setup sur ces mêmes primitives. Si vous voulez nettoyer un objet de tout setup utilisez le script de gomme :


Cliquez ce bouton ou survolez le contenu pour afficher le spoiler
Code PHP:

////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                            //
//                                 Articulation Gomme V 1.01                                    //
//                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////
//                          Copyright (c) 2012 by Bestmomo Lagan                              //
////////////////////////////////////////////////////////////////////////////////////////////////
//   This program is free software: you can redistribute it and/or modify                     //
//    it under the terms of the GNU General Public License as published by                    //
//    the Free Software Foundation, either version 3 of the License, or                       //
//    (at your option) any later version.                                                     //
//                                                                                            //
//    Articulations is distributed WITHOUT ANY WARRANTY;                                      //
//    See the GNU General Public License for more details.                                    //
//                                                                                            //
//    To get a copy of the GNU General Public License, see <http://www.gnu.org/licenses/>.    //
////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////
//                Dont change code below unless you know what you do                          //
////////////////////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------
//        Paramètres primitive
// -----------------------------------------------
string get_texte(integer id) {
    return 
llList2String(llGetLinkPrimitiveParams(id, [PRIM_TEXT]), 0);
}
unset_texte(integer id) {
    
llSetLinkPrimitiveParamsFast(id, [PRIM_TEXT"", <0,0,0>, 0]);
}

// -----------------------------------------------
//        Etat unique
// -----------------------------------------------
default
{
    
state_entry() {
        
llOwnerSay(llGetScriptName() + " processing cleaning...");
        
// Recherche des primitives avec un setup
        
integer n llGetNumberOfPrims();
        
integer i;
        for(
2<= n; ++i) { 
            
string s get_texte(i);
            if(
!= "") if(llGetSubString(s00) == "!"unset_texte(i);
        }
        
llOwnerSay("Object is now clean !");
        
llRemoveInventory(llGetScriptName());
    }



J'ai mis quelques commentaires dans les script pour les courageux qui voudraient savoir comment ça fonctionne .

Edit : j'ai ajouté une documentation complète au format PDF .
Fichiers attachés
articulations.pdf (689,9 Ko, 69 affichages)

Dernière modification par bestmomo ; 02/11/2012 à 10h00. Motif: Mise à jour fichier pdf
@bestmomo.

Je savais que j'avais une application pour ce système de scripts, mais le temps me manquait, pour cause de trébuchet à terminer afin que Black Cats puissent scripter l'engin (ses premières versions de script sont juste bluffantes et je suis impatient de le voir donner sont feu vert à une présentation).

Donc ce matin je me suis lancé, l'idée est simple, il s'agit de volets articulés.

Snapshot_005.jpg

Donc comme on le voit, dans la fenêtre il y a 4 volets le rouge et le jaune sont liés d'une part et le vert et le bleu d'autre part.

Le rouge s'ouvre côté gauche de l'image et le jaune vient se replier dessus (premier setup)

Le bleu s'ouvre côté droit de l'image et le vert vient se replier dessus (second setup)

Snapshot_004.jpg

L'ensemble part de la bonne position pour aboutir à la bonne position sauf que, pendant le mouvement d'ouverture, le volet vert tourne à l'envers de ce qui devrait être (comme si on lui imposait un sens de rotation erroné).

À gauche on a un effet "accordéon" (parfait) alors qu'à droite le volet vert passe à travers le bleu pour arriver à la bonne position.

PS : pour moi, les axes ne s'effacent jamais automatiquement (pas grave puisqu'en les effaçant à la main ça marche).
Pour les axes qui doivent disparaître j'avais commenté la ligne correspondante pendant mes essais et j'ai oublié de la dé-commenté ensuite, maintenant c'est fait .

Pour tes volets j'ai fait un test, en fait le souci vient de l’ambiguïté qu'il peut y avoir avec une rotation de 180°, la primitive risque de tourner dans l'autre sens. Au lieux de prendre 180° j'ai pris 179° et je n'ai plus eu de problème. Une astuce pour avoir une rotation de plus de 180° d'une primitive par rapport à une autre peut consister à ajouter une primitive invisible et du coup un autre axe, mais je n'ai pas testé par contre.

Moralité pour tes volets limite toi à une rotation de 179° pour le deuxième panneau et ça devrait rouler .
Ça fonctionne nickel !!!

Bravo Monsieur le Best .

Et finalement, 180° c'est trop parfait, ça existe pas, 176, 177, 178 ou 179, c'est beaucoup plus crédible...
Tiens, comme notre ami scripteur a l'air de ronronner sur son douillet coussin...

J'en remet une couche...

Les volets s'ouvrent impeccable en grand pour aérer, mais pour les chaudes après midi d'été, cette position serait la bonne

Snapshot_003.jpg

Donc comment conjuguer les deux types d'ouverture...
Citation :
Publié par bestmomo
Déjà mon système n'est pas fait pour ça, les axes doivent être tous parallèles .
Ben oui, je sais, sinon j'aurais rajouté un axe...

Mais c'est pour ça que je pose la question, on sait jamais, dans la mesure ou c'est deux commandes différentes, il y a t il une solution ?

/me se retire doucement sur la pointe des pieds afin de ne pas provoquer la fureur du félin, mais espère néanmoins que sa requête sera étudiée...
Citation :
Publié par anpton
Mais c'est pour ça que je pose la question, on sait jamais, dans la mesure ou c'est deux commandes différentes, il y a t il une solution ?
Le principal souci vient du fait que j'ai prévu la mémorisation des paramètres dans le texte flottant, du coup il devient impossible d'effecteur deux setup pour une même primitive. Comme quoi un avantage peut devenir un inconvénient .

Il serait dommage de se priver de ce style de mémorisation qui assure un fonctionnement dans tous les cas de figure. Il faut donc un système différent pour gérer ton ouverture estivale, d'autant que plusieurs primitives doivent bouger de conserve dans ce cas.
Ton système est génial, Bestmomo, en plus, le mouvement est souple et visuellement très esthétique, je pense qu'il y a un bon nombre d'applications à mettre en place avec.

Simplement je cherche un script pour obtenir cet autre positionnement, sans foutre en l'air l'ouverture "accordéon".

@Pi78 : Va pas nous le mettre en colère stp...
Répondre

Connectés sur ce fil

 
1 connecté (0 membre et 1 invité) Afficher la liste détaillée des connectés