|
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 :
//////////////////////////////////////////////////////////////////////////////////////////////// // // // 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_NAME, nom]);} set_couleur(vector couleur) {llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_COLOR, ALL_SIDES, couleur, 1]);} 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 channel, string name, key id, string message) { if(channel == CANAL_AXE) { list l = llParseString2List(message, [":"], []); // Retour de demande de nom if(llList2String(l, 0) == "TEST_BACK") l_noms += llList2String(l, 1); // Réception de demande de nom else if(llList2String(l, 0) == "TEST") llWhisper(CANAL_AXE, "TEST_BACK:" + get_nom()); } else if(channel == CANAL_SETUP + 1 && 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(n > 5) { llOwnerSay("Limite dépassée ! Pas plus de 6 axes !"); llDie(); } else { while(n--) { string nom = llList2String(l_noms, n); l += (integer)llGetSubString(nom, -1, -1); } i_id = (integer)llListStatistics(LIST_STAT_MAX, l) + 1; set_nom("axe_" + (string)i_id); set_texte(get_nom()); set_couleur(llList2Vector(COULEURS, i_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 channel, string name, key id, string message) { if(message == "DIE") llDie(); list l = llParseString2List(message, ["@"], []); // Est-ce que c'est pour moi ? if((integer)llList2String(l, 1) == i_id) { // Réponse à demande de position initiale if(llList2String(l, 0) == "ASK") llSay(CANAL_SETUP, "SET@" + (string)llGetPos() + "@" + (string)(llGetPos() + <.0,.0,1.0> * llGetRot())); // Ordre de mouvement else if(llList2String(l, 0) == "MOVE") llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_POSITION, (vector)llList2String(l, 2)]); } } }
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 :
//////////////////////////////////////////////////////////////////////////////////////////////// // // // 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(), texte, menu, i_canal_menu); } // Menu de sélection des liaisons menu_liaisons() { list l = ["Next"]; if(i_step) l = ["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 id, vector col) { llSetLinkPrimitiveParamsFast(id, [PRIM_TEXT, "Link to axe_" + (string)i_step, col, 1]); } 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(; i < n; ++i) { integer id = llList2Integer(l_link, i); 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_int, i); } 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(i = 2; i <= n; ++i) { string s = get_texte(i); if(s != "") { if(llGetSubString(s, 0, 0) == "!") { l_link_setup += i; l_id += (integer)llGetSubString(s, 1, 1); } } } // Détermination de l'id de ce setup if(llGetListLength(l_id)) s_setup = (string)((integer)llListStatistics(LIST_STAT_MAX, l_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_1, n)) + "@" + compact_info(llList2Vector(l_v_centre_state_2, n)) + "@" + compact_info(llRot2Euler(llList2Rot(l_r_rot_state_1, n)) * RAD_TO_DEG) + "@" + compact_info(llRot2Euler(llList2Rot(l_r_rot_state_2, n)) * RAD_TO_DEG) + "@" + compact_info(llList2Vector(l_v_pos_state_1, n)) + "@" + compact_info(llList2Vector(l_v_pos_state_2, n)) + "@" + compact_info(llRot2Euler(llList2Rot(l_vec_rot, n)) * RAD_TO_DEG); llSetLinkPrimitiveParamsFast(llList2Integer(l_link, n), [PRIM_TEXT, s, ZERO_VECTOR, 0]); } } string compact_info(vector v) { return get_part(v.x) + "," + get_part(v.y) + "," + get_part(v.z); } string get_part(float f) { if(f == .0) return "0"; else return llGetSubString((string)f, 0, 5); }
// ----------------------------------------------- // 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 channel, string name, key id, string message) { // Réception messages des axes list l = llParseString2List(message, ["@"], []); // Récupération des données de l'axe if(llList2String(l, 0) == "SET") { vector v_centre_global = (vector)llList2String(l, 1); rotation r_global = (rotation)llList2String(l, 2); 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_step) v_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 == 0) llOwnerSay("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 != 1 && 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 && i_bis == -1) { i_step = 0; integer n = llGetListLength(l_v_centre_state_1); for(; i_step < n; ++i_step) set_texte(llList2Integer(l_link, i_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 channel, string name, key id, string 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_link, n)); // 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(; i < n; ++i) { integer id_link = llList2Integer(l_link, i); rotation r = llAxisAngle2Rot(v_axe, f_angle * DEG_TO_RAD); vector v_tournant = llList2Vector(l_v_pos_state_2, i) - llList2Vector(l_v_centre_state_2, i_step); if(i == i_step) l_vec_rot = llListReplaceList(l_vec_rot, [r], i, i); llSetLinkPrimitiveParamsFast(id_link, [ PRIM_POSITION, llList2Vector(l_v_centre_state_2, i_step) + v_tournant * r, PRIM_ROT_LOCAL, llList2Rot(l_r_rot_state_2, i) * r]); // Encore un axe if(i < n - 1) { v_tournant = llList2Vector(l_v_centre_state_2, i + 1) - llList2Vector(l_v_centre_state_2, i_step); vector axe_pos = llList2Vector(l_v_centre_state_2, i_step) + v_tournant * r; // Mémorisation de la position l_v_centre_state_int = llListReplaceList(l_v_centre_state_int, [axe_pos], i + 1, i + 1); // Ordre de mouvement à l'axe llSay(CANAL_SETUP + 1, "MOVE@" + (string)(i + 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 :
//////////////////////////////////////////////////////////////////////////////////////////////// // // // 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 r0, rotation r1, float t){ float f = (1 - llCos(t * PI)) / 2; float f_ang = llAngleBetween(r0, r1); if(f_ang > PI) f_ang -= TWO_PI; return r0 * llAxisAngle2Rot(llRot2Axis(r1 / r0) * r0, f_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(; i < n; ++i) { if(i_back) r = r_cos(llList2Rot(l_vec_rot, i), ZERO_ROTATION, step); else r = r_cos(ZERO_ROTATION, llList2Rot(l_vec_rot, i), step); r_tot *= r; vector v_tournant = llList2Vector(l_v_pos_state_1, i) - llList2Vector(l_v_centre_state_1 , i); vector pos = v_centre + v_tournant * r_tot; if(i) l_params += [PRIM_LINK_TARGET, llList2Integer(l_link, i)]; l_params += [PRIM_POSITION, pos, PRIM_ROT_LOCAL, llList2Rot(l_r_rot_state_1, i) * r_tot]; // Encore un axe if(i < n - 1) { v_tournant = llList2Vector(l_v_centre_state_1 , i + 1) - llList2Vector(l_v_centre_state_1 , i); v_centre += v_tournant * r_tot; } } llSetLinkPrimitiveParamsFast(llList2Integer(l_link, 0), l_params); llSleep(TEMPS_BASE); } }
// ----------------------------------------------- // Manoeuvre de l'objet // ----------------------------------------------- // Test de première position integer test_first() { return get_pos(llList2Integer(l_link, 0)) == llList2Vector(l_v_pos_state_1, 0); }
// Test de seconde position integer test_second() { return get_pos(llList2Integer(l_link, 0)) == llList2Vector(l_v_pos_state_2, 0); }
// Manoeuvre sur clic action_click() { // Vers second if(test_first()) { go_second(); } // vers premier else if(test_second()) { if(RETURNTIME == .0) go_first(); } // Cas où il y a eu une modification de build else { llSetText("", ZERO_VECTOR, 0); llResetScript(); } }
// Passage en seconde position go_second() { transition(FALSE); // Fixation de l'état integer n = llGetListLength(l_link); while(n--) { llSetLinkPrimitiveParamsFast(llList2Integer(l_link, n), [ PRIM_POSITION, llList2Vector(l_v_pos_state_2, n), PRIM_ROT_LOCAL, llList2Rot(l_r_rot_state_2, n)]); } if(SECONDSOUND != "none") llTriggerSound(SECONDSOUND, 1.0); else if(RETURNTIME != .0 && SENSOR_RANGE == .0 && !AUTO) llSetTimerEvent(RETURNTIME); }
// Passage en première position go_first() { transition(TRUE); // Fixation de l'état integer n = llGetListLength(l_link); while(n--) { llSetLinkPrimitiveParamsFast(llList2Integer(l_link, n), [ PRIM_POSITION, llList2Vector(l_v_pos_state_1, n), PRIM_ROT_LOCAL, llList2Rot(l_r_rot_state_1, n)]); } if(FIRSTSOUND != "none") llTriggerSound(FIRSTSOUND, 1.0); }
// ----------------------------------------------- // Détermination de l'index du script // ----------------------------------------------- integer trouve_index() { list l = llParseString2List(llGetScriptName(), [" "], []); if(llGetListLength(l) == 1) return 0; else return (integer)llList2String(l, 1); }
// ----------------------------------------------- // 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(i = 2; i <= n; ++i) { string s = get_texte(i); if(s != "") { if(llGetSubString(s, 0, 1) == "!" + s_id) { l_textes += s; l_id += i; } } } // Traitement des informations n = llGetListLength(l_textes); if(n) { i = 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_textes, n); list l = llParseString2List(s, ["@"], []); integer id = (integer)llGetSubString(s, 2, 2); l_link = llListReplaceList(l_link, [llList2Integer(l_id, n)], id, id); l_v_centre_state_1 = llListReplaceList(l_v_centre_state_1, [get_vector(llList2String(l, 1))], id, id); l_v_centre_state_2 = llListReplaceList(l_v_centre_state_2, [get_vector(llList2String(l, 2))], id, id); l_r_rot_state_1 = llListReplaceList(l_r_rot_state_1, [get_rotation(llList2String(l, 3))], id, id); l_r_rot_state_2 = llListReplaceList(l_r_rot_state_2, [get_rotation(llList2String(l, 4))], id, id); l_v_pos_state_1 = llListReplaceList(l_v_pos_state_1, [get_vector(llList2String(l, 5))], id, id); l_v_pos_state_2 = llListReplaceList(l_v_pos_state_2, [get_vector(llList2String(l, 6))], id, id); l_vec_rot = llListReplaceList(l_vec_rot, [get_rotation(llList2String(l, 7))], id, id); } return TRUE; } return FALSE; }
rotation get_rotation(string s) { return llEuler2Rot((vector)("<" + s + ">") * DEG_TO_RAD); } vector get_vector(string s) { return (vector)("<" + s + ">"); }
// ----------------------------------------------- // 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_link, n), [ PRIM_POSITION, llList2Vector(l_v_pos_state_1, n), PRIM_ROT_LOCAL, llList2Rot(l_r_rot_state_1, n)]); } // Sensor éventuel if(SENSOR_RANGE != .0 && !API) llSensorRepeat("", NULL_KEY, AGENT, SENSOR_RANGE, PI, SENSOR_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 == .0) action_click(); else if(test_first()) llInstantMessage(k, CLICKMESSAGE); } else llInstantMessage(k, ACCESSMESSAGE); } }
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_number, integer number, string message, key id) { if(number == API_CLICK && SENSOR_RANGE == .0) action_click(); else if(number == API_GO_POS_1) go_first(); else if(number == API_GO_POS_2) go_second(); else if(number == API_GET_POS) { llMessageLinked(LINK_THIS, API_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_STOP) i_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 :
//////////////////////////////////////////////////////////////////////////////////////////////// // // // 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(i = 2; i <= n; ++i) { string s = get_texte(i); if(s != "") if(llGetSubString(s, 0, 0) == "!") 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 .
Dernière modification par bestmomo ; 02/11/2012 à 10h00.
Motif: Mise à jour fichier pdf
|