probléme dans l'ordre de lecture du script.

Répondre
Partager Rechercher
bonjour tout le monde!

je vous expose mon projet avant le problème:

je travail sur un script pour un déplacement programmé, dans l'idée un objet ( comme un robot....) seras rezzé et va faire son parcourt avant de die, alors j'ai réussi non sans mal a établir un script, bon pas forcément le meilleur mais vue le niveau en script....enfin bref ....la ou j'ai un souci reste que je souhaite une fois le déplacement prévu effectué, que l'objet en question sois supprimé donc llDie();

voila le script en question :

Cliquez ce bouton ou survolez le contenu pour afficher le spoiler

// les listes rawoffsets sont représenté sur la x, y, z donc : list rawOffsets = [ <x,y,z> ...

list rawOffsets =
[ <1.0,0.0,0.0>
,<0.0,1.0,0.0>
, <-1.0,0.0,0.0>
, <0.0,-1.0,0.0>
,<1.0,0.0,0.0>
,<0.0,1.0,0.0>
, <-1.0,0.0,0.0>
, <0.0,-1.0,0.0>

];

vector U;
vector V;

default
{
touch_start(integer total_number)
{
list kfmList;
U = llRot2Fwd( llGetRot());
integer offsetIdx;
integer offsetCount = llGetListLength(rawOffsets);
while (offsetIdx < offsetCount)
{
V = llList2Vector(rawOffsets, offsetIdx++) * llGetRot();
kfmList += [ ZERO_VECTOR, llRotBetween( U, V), 1.0];
kfmList += [V, ZERO_ROTATION, 1.0];
U = V;
}
kfmList += [ ZERO_VECTOR, llRotBetween( U, llRot2Fwd( llGetRot())), 1.0];
llSetKeyframedMotion( kfmList, []);
llDie();
}
}


problème pour moi l'objet es die avant même de faire le parcours prévu,je ne comprend pas du tout pourquoi. j'ai donc grand besoin de vos lumières!

d'avance merci!
Ce que tu fais est la chose suivante :

1 - tu prépares ta liste de déplacements
2 - tu démarres le déplacement qui, si j'ai bien regardé, devrait prendre 17 secondes, et immédiatement après le top départ, tu exécutes le llDie.

C'est normal que ton déplacement n'ait pas le temps de s'effectuer.

Tu dois mettre ton llDie dans un event séparé.
Soit un timer, que tu démarres en même temps que le mouvement, soit un moving_end.
Cliquez ce bouton ou survolez le contenu pour afficher le spoiler
P.S.
Tu devrais utiliser la balise PHP, pour publier ton script, plutôt que le spoiler
Code PHP:

default
{
    
touch_start(integer total_number)
    {
    
    
//(...)
    //garder tout ce que tu avais ici
    //(...)
    
    //a la fin, tu démarres le moteur,...
    
llSetKeyframedMotionkfmList, []);
    
// et tu démarres aussi le chronomètre
    
llSetTimerEvent(offsetCount*2.0+2.0);
    }

    
//quand le chrono te dit que la durée du déplacemement
    //est atteinte, tu fais péter la dynamite
    
timer()
    {
    
llDie();
    }


Il est un peu hasardeux de se fier à une temporisation pour déterminer la fin d'un mouvement généré avec un keyframed. Il vaut mieux passer par l'événement moving_end.
A condition, dans ce cas-là, de prendre des précautions supplémentaires. Ne serait-ce que pour éviter qu'il ne disparaisse dès que tu le rezzes .

Après, tout dépend de l'alternative de comportement que l'on privilégie, dans les rares cas d'utilisation anormale.
Oui, mais dans ce cas, qu'est ce qu'il importe vraiment de faire si jamais le robot n'arrivait pas à la destination souhaitée, dans le temps imparti ?

Pour résoudre le problème du llDie dans l'event moving-end qui se déclenche lors du rez, on peut toujours ajouter une condition qu'on met à FALSE lors du rez, et à TRUE une fois le mouvement démarré, et soumettre le llDie à cette condition.

Mais après tout, on ne sait pas comment le robot est utilisé.
Est-ce qu'il va vraiment démarrer lors du touch ? Ou dès qu'il est rezzé ?
Est ce qu'un nouveau robot est rezzé une fois que le premier a démarré ? Dans ce cas, la priorité serait plutôt de s'assurer que le premier disparaisse quoiqu'il arrive, plutôt que de l'en empécher en cas de problème.

Calculer les coordonnées de la destination d'arrivée n'est pas ce qu'il y de plus simple non plus. Ni sans soulever de nouveaux problèmes. Il suffit d'une bosse dans le relief, et la position calculée peut se trouver à l'intérieur de la bosse, et le pauvre robot ne pourra jamais atteindre cette destination, et risque de se morfondre pendant des siècles.

Bof. On peut toujours blinder le script, prévoir ce qu'il arriverait en cas de troisième guerre mondiale, de l'extinction des ressources en énergie fossile, de passage d'un quidam frustré de sa dernière soirée...

Mais est-ce vraiment utile ? Souhaitable ?
Tant qu'on ne connait pas le contexte, et les priorités, on ne peut pas vraiment trancher.
Il me semble, mais il se peut que je me trompe, qu'un llSetKeyframedMotion avec un parcours 1, suivi d'un llSetKeyframedMotion avec un parcours 2 (à la place du llDie donc) ferait s'enchaîner de façon successive les 2 parcours (le 2e SKFM "attendant" que le 1er ait fini de s'effectuer).
Si c'est bien le cas, un 2e llSetKeyframedMotion suivi d'un llDie ne permettrait-il pas d'éviter les inconvénients des solutions envisagées?

EDIT: non, cela ne marche pas, j'ai essayé. La mort n'attend pas

Dernière modification par Worstbobo ; 08/10/2014 à 14h45.
oula oula ^^

bon je vais prendre les choses dans l'ordre :

j'ai travaillé grâce au conseils de black cats mon script :

Citation :
Ce que tu fais est la chose suivante :

1 - tu prépares ta liste de déplacements
2 - tu démarres le déplacement qui, si j'ai bien regardé, devrait prendre 17 secondes, et immédiatement après le top départ, tu exécutes le llDie.

C'est normal que ton déplacement n'ait pas le temps de s'effectuer.

Tu dois mettre ton llDie dans un event séparé.
Soit un timer, que tu démarres en même temps que le mouvement, soit un moving_end.
avec le coup de pouce du wiki j'en suis arrivé la :

Code PHP:

float VITESSEdeplacement 1.0;
float VITESSErotation 1.0;


list 
rawOffsets =
[
<
1.0,0.0,0.0>
,<
0.0,1.0,0.0>
, <-
1.0,0.0,0.0>
, <
0.0,-1.0,0.0>



];


default
{
touch_start(integer total_number)
{
  
list 
kfmList;

integer offsetIdx;
integer offsetCount llGetListLength(rawOffsets);

while (
offsetIdx offsetCount)
{
   
kfmList += [llList2Vector(rawOffsetsoffsetIdx++) * llGetRot()] + [ZERO_ROTATION] + [VITESSEdeplacement];  
  
    
kfmList += [ZERO_VECTOR] +[llEuler2Rot(<0.0,0.0,PI/2>)] + [VITESSErotation];



}

llSetKeyframedMotionkfmList, []);
}
 
moving_end()
 {
llDie();

}

Alors effectivement tout fonctionne déjà mieux donc déjà la merci black cats!

maintenant je vois un complément avec un timer pour contrôlé la position de l'objet, mais autant je comprend le "llSetTimerEvent" qui contrôle sous condition de offsetCount par contre j'ai du mal a saisir le "offsetCount*2.0+2.0" .... *2.0+2.0???

Pourrais tu m'expliqué cet élément? et pourquoi
bestmomo a un doute sur le bon fonctionnement du calcul de déplacement ?

Dernière modification par mappa story ; 08/10/2014 à 18h39.
Dans le wiki il est précisé :

Cliquez ce bouton ou survolez le contenu pour afficher le spoiler
llSetKeyframedMotion is implemented in terms of frames and not real time.


Donc s'il se produit un phénomène de dilatation temporelle, ce qui est assez fréquent sur SL avec le lag, le fait de mesurer le temps ne donnera pas une indication précise sur le nombre de frames utilisées et tu risques de croire que le mouvement est terminé alors que ce n'est pas vrai. C'est pour cette raison que je préconise plutôt d'implémenter un événement qui se déclenche lorsque le mouvement est réellement terminé.
En même temps, le moving end (tout comme le timer) interdit tout STOP ou toute PAUSE durant le parcours (possibilités prévues dans SKFM). Ce qui l'exclut un peu comme "vraie" solution, non?
Et si un avatar s'asseoit sur l'objet en déplacement ou si l'objet est "retenu" par un clic droit, cela ne joue pas sur le moving-end?
Citation :
Publié par bestmomo
Dans le wiki il est précisé :
Donc s'il se produit un phénomène de dilatation temporelle, ce qui est assez fréquent sur SL avec le lag, le fait de mesurer le temps ne donnera pas une indication précise sur le nombre de frames utilisées et tu risques de croire que le mouvement est terminé alors que ce n'est pas vrai.
Certes.
L'incertitude (somme toute relative) sur la durée du mouvement, peut être gênante dans certains cas, si on doit démarrer une autre action à la suite du mouvement, et si ça pose un réel problème de démarrer la nouvelle action alors que le mouvement n'est pas tout à fait terminé.

Mais dans le cas présent, le robot effectue un trajet, puis s'auto-détruit.
J'avais ajouté une seconde à la durée théorique du déplacement, pour avoir de la marge.
Je ne pense pas que beaucoup de personnes se rendent compte que le robot reste une seconde de plus après la fin du déplacement, si la durée est optimale, ou s'il disparaît une seconde trop tôt, en cas de lag important.

Par ailleurs, l'utilisation du moving_end introduit de nouveaux problèmes, j'en avais évoqué quelques uns plus haut, étant donné qu'il se déclenche :
- lors d'un rez
- lorsqu'on fait un click droit sur l'objet
- lorsqu'on duplique l'objet par majuscule/déplacer
-(et autres...?)

Le script de Mappa ci-dessus est une illustration d'un de ces problèmes.
Si on prend le robot dans son inventaire, on ne pourra plus jamais le rezzer : quand on le rez, l'événement moving_end se déclenche, et il est détruit immédiatement.

Si on s'amuse à faire un click droit sur le robot, ça le détruit également.

D'un autre côté, on a une incertitude sur la durée du mouvement.
Il y a le problème de lag évoqué par Best.
Par un click gauche, on peut retenir l'objet, et allonger la durée du mouvement.

Quand j'utilise le llSetKeyframedMotion dans un script, j'utilise souvent un double test : le moving_end, doublé d'un timer, quand les incertitudes (sur la durée, mais aussi sur la position d'arrivée) risquent de poser de réels problèmes.

Dans le cas présent, ça ne me paraissait pas utile.
L'avantage que je vois à l'utilisation du timer, dans le cas présent, c'est surtout que c'est une solution simple et fiable, si on part du principe que la priorité, c'est que le robot disparaisse effectivement. La modification que je proposais rajoutait une seule instruction supplémentaire, plus un timer_event.

Si on veut tuer le robot lors du moving_end, on peut faire quelque chose comme ça :
Code PHP:

float VITESSEdeplacement 1.0;
float VITESSErotation 1.0;
integer kill;

list 
rawOffsets =
[
<
1.0,0.0,0.0>
,<
0.0,1.0,0.0>
, <-
1.0,0.0,0.0>
, <
0.0,-1.0,0.0>
];


default
{
    
state_entry()
    {
    
llSetTimerEvent(0.0);
    
llSetKeyframedMotion([],[]);
    
kill FALSE;
    }
    
    
touch_start(integer total_number)
    {
    
state mouvement;
    }
}
    
    
state mouvement
{
    
on_rez(integer n)
    {
    
state default;
    }
    
    
state_entry()
    {
    list 
kfmList;
    
integer offsetIdx;
    
integer offsetCount llGetListLength(rawOffsets);
    while (
offsetIdx offsetCount)
        {
        
kfmList += [llList2Vector(rawOffsetsoffsetIdx++) * llGetRot()] + [ZERO_ROTATION] + [VITESSEdeplacement];  
        
kfmList += [ZERO_VECTOR] +[llEuler2Rot(<0.0,0.0,PI/2>)] + [VITESSErotation];
        }
    
llSetTimerEvent(2.0*(VITESSEdeplacement+VITESSErotation)-1.0);
    
llSetKeyframedMotionkfmList, []);
    }
    
    
timer()
    {
    if (
killllDie();
    
kill TRUE;
    }
    
    
moving_end()
    {
    if (
killllDie();
    }

Il y a deux "state". Ca permet de désactiver le touch lorsque le robot est en mouvement. Si on clique dessus pendant le mouvement, le robot n'arrivera pas à la bonne destination, puisqu'on interrompt le mouvement, pour redémarrer un nouveau déplacement relatif en partant de là ou on l'a interrompu.
Ca évite aussi la destruction immédiate du robot lors du rez.


Mais il faut empêcher qu'on puisse le tuer par un simple click droit pendant le mouvement (et aussi, mais c'est moins important, qu'il soit détruit en cas de copie par maj/glisser).
D'où la variable kill, qui vaut FALSE au début du mouvement.

Un timer (encore lui ) d'une durée égale à la durée théorique moins une seconde, est indispensable pour mettre la variable kill à TRUE peu avant la fin prévue du mouvement, autorisant ainsi la destruction dès que le moving_end arrive.
Tant qu'à faire, j'ai rajouté une ligne
Code PHP:

if (killllDie(); 

Ainsi, si pour une raison, quelle qu'elle soit, le robot n'a pas été tué au cours d'un moving_end, après presque le double du temps théorique, il le sera par le timer.

Bref, je reste convaincu que la solution du timer seul, était, dans le cas présent, préférable à la solution du moving end seul en raison des nouveaux problèmes qu'il amène.
La combinaison des deux étant bien sûr la plus aboutie.

Citation :
Publié par mappa story
(...) par contre j'ai du mal a saisir le "offsetCount*2.0+2.0" .... *2.0+2.0???

Pourrais tu m'expliqué cet élément?
C'est le calcul de la durée théorique du mouvement.
Dans la boucle while de ton premier script, tu rajoutes deux déplacements d'une durée de 1.0s à chaque itération. Tu rajoutes un autre mouvement après la boucle.
Ce qui donne une durée théorique de offsetCount*2.0+1.0
Avec une seconde supplémentaire de marge, ça donne offsetCount*2.0+2.0

Dans ton dernier script, la durée théorique est de 2.0*(VITESSEdeplacement+VITESSErotation)
Mais cette fois, comme le timer sert à autoriser la destruction quand le moving_end aura lieu, il faut que le délai soit plus court que la durée théorique.
Ce qui donne 2.0*(VITESSEdeplacement+VITESSErotation)-1.0

C'était mon pavé du soir. Pour ceux qui ont le courage de lire des romans

Dernière modification par black cats ; 08/10/2014 à 23h27.
merci pour tes précieuses explications black cats! j'aime comprendre ce que je tente de créé en script et ce que j'utilise.

il reste uniquement a réglé le souci de rotation , j'ai remarqué pendant les tests que le mobile ne fais pas toujours face au déplacement.

j'avais pris pour l'exemple un déplacement simple de 1 mètre par 1 mètre mais après avoir voulu programmé une plus longue liste le drame !!!! , je me retrouve avec un petit véhicule qui se déplace de coté , parfois en marche arrière grrrrr...en tout cas je suis loin d'un mobile qui fais face a son déplacement , mais je ne lache rien ;-)

dans tout les cas merci a vous tous pour vos conseils.
pppffff

j'ai tout tourné,tout tenté je ne comprend pas....

dans mes recherches entre le wiki et le forum je suis tombé sur un post avec le mème problème que le mien:

"https://forums.jeuxonline.info/showthread.php?t=972124"

j'ai donc étudié les conseils de bestmomo et pallas mais rien a faire , surtout que je build et script sur open sim ce qui n'aide pas forcément vue que llLookAt n'es pas encore accepté , j'ai donc opté pour llRotLookAt.

problème sur ma tentative mon prim deja ne se tourne pas vers la direction mais en plus ne tourne mème plus du tout pendant la trajectoire...

voila ou j'en suis :

Code PHP:

float VITESSEdeplacement 1.0;
float VITESSErotation 1.0;
integer kill;

list 
rawOffsets =
[
<
1.0,0.0,0.0>
,<
0.0,1.0,0.0>
, <-
1.0,0.0,0.0>
, <
0.0,-1.0,0.0>
, <-
1.0,0.0,0.0>
,<
0.0,1.0,0.0>
];


default
{
    
state_entry()
    {
    
llSetTimerEvent(0.0);
    
llSetKeyframedMotion([],[]);
    
kill FALSE;
    }
    
    
touch_start(integer total_number)
    {
    
state mouvement;
    }
}
    
    
state mouvement
{
    
on_rez(integer n)
    {
    
state default;
    }
    
    
state_entry()
    {
        
vector destination llVecNorm(<1.0,0.0,0.0> );
        
rotation r llRotBetween(<1.0,0.0,0.0>, destination);
    list 
kfmList;
    
integer offsetIdx;
    
integer offsetCount llGetListLength(rawOffsets);
    while (
offsetIdx offsetCount)
        {
        
kfmList += [llList2Vector(rawOffsetsoffsetIdx++) * llGetRot()] + [ZERO_ROTATION] + [VITESSEdeplacement];  
        
//kfmList += [ZERO_VECTOR] +[llEuler2Rot(<0.0,0.0,PI/2>)] + [VITESSErotation];
        
llRotLookAt(r1.0.5);
        }
    
llSetTimerEvent(2.0*(VITESSEdeplacement+VITESSErotation)-1.0);
    
llSetKeyframedMotionkfmList,[KFM_ROTATION]);
    
    }
    
    
timer()
    {
    if (
killllSay(0,"top");
    
kill TRUE;
    }
    
    
moving_end()
    {
    if (
kill)llSay(0,"top");
    }

je ne suis pas contre pour un petit coup de pouce ( encore) , je vous remercie d'avance!
Salut,

Ce n'est pas très clair ce que tu veux faire. Si tu utilises un keyframed tu n'as besoin de rien d'autre pour piloter ton objet puisque tu peux gérer la position et la rotation à chaque étape. D'autre part si tu interfères dans ce mouvement avec d'autres fonctions le résultat sera imprévisible. Et ton llRotLookAt dans ta boucle est on ne peut plus étrange.
bonsoir bestmomo

dans l'idée du mobile je souhaite juste maintenant a forcé le prim ou l'ensemble de prim a suivre de face la direction , donc si je tourne a droite je m'oriente a droite avant d'avancé vers ma droite , si je tourne a gauche je m'oriente a gauche avant d'avancé sur ma gauche ,ou mème si je décide de faire demi tour il s'oriente toujours face a la direction....etc etc

Citation :
Si tu utilises un keyframed tu n'as besoin de rien d'autre pour piloter ton objet puisque tu peux gérer la position et la rotation à chaque étape
j'ai regardé le wiki et différent post de jol ou tu en parle déjà mais je n'arrive pas a combiné les vecteurs de déplacement et les vecteurs de rotation dans une liste , j'admet que l'idéal serais de par exemple dans une liste lui dire , tu avance de 10 mètres , ensuite tu tourne sur 45 degrés a droite....ensuite tu avance de 5 mètres ....ensuite tu tourne de 90 degrés a gauche ....etc etc ....mais j'admet aussi n'avoir aucune idée de comment écrire ce script....

Dans un élément d'une liste pour le keyframed tu as 3 paramètres :

  • déplacement,
  • rotation,
  • durée
Tu peux très bien commencer par une certaine rotation et un déplacement nul, puis suivre avec un certain déplacement et une rotation nulle. Tu auras ainsi ton objet qui tourne sur place, puis après qui avance.
bonjour.

Citation :
Tu peux très bien commencer par une certaine rotation et un déplacement nul, puis suivre avec un certain déplacement et une rotation nulle
ok mais donc dans la liste rawOffsets il es donc possible de renseigné une direction ensuite une rotation? de faire une nuance entre les deux ,le tout dans une méme liste ?
Tu peux faire deux listes : une pour les déplacements et une pour les rotations, comme ça :

Code PHP:

float VITESSEdeplacement 1.0;
float VITESSErotation 1.0;


list 
OffsetsPos =  [
    <
1.0,0.0,0.0>,
    <
0.0,1.0,0.0>,
    <-
1.0,0.0,0.0>,
    <
0.0,-1.0,0.0>
        ];

list 
OffsetRot = [
    <
0.000000.000000.707110.70711>,
    <
0.000000.000000.707110.70711>,
    <
0.000000.000000.707110.70711>,
    <
0.000000.000000.707110.70711>
        ];

rotation NormRot(rotation Q)
{
    
float MagQ llSqrt(Q.Q.Q.Q.Q.Q.Q.Q.s);
    return <
Q.MagQQ.MagQQ.MagQQ.MagQ>;
}

default
{
    
touch_start(integer total_number)
    {
        list 
kfmList;
        
integer offsetIdx;
        
integer offsetCount llGetListLength(OffsetsPos);

        while (
offsetIdx offsetCount)
        {
            
kfmList += [llList2Vector(OffsetsPosoffsetIdx) * llGetRot(), ZERO_ROTATIONVITESSEdeplacement];
            
kfmList += [ZERO_VECTORNormRot(llList2Rot(OffsetRotoffsetIdx++)), VITESSErotation];
        }

        
llSetKeyframedMotionkfmList, []);
    }
    
    
moving_end()
    {
        
llOwnerSay("Fin du déplacement");
    }

La normalisation des rotations est à prévoir systématiquement pour éviter les surprises.
bonsoir tout le monde!

merci a toi bestmomo et désolé de ma réponse tardive mais en tout cas ormi juste un détail ton script fonctionne super bien , néanmoins je comprend mieux pourquoi je n'arrive a rien avec ce script depuis le début..... il me manque juste des mois de formation pour y arrivé..... ( pfffff!)
Bonjour tout le monde ,

oups oui encore moi , j'aurais encore deux questions au sujet de ce script

-déjà je tente de comprendre la partie de normalisation des rotations :

"float MagQ = llSqrt(Q.x * Q.x + Q.y * Q.y + Q.z * Q.z + Q.s * Q.s);
return <
Q.x / MagQ, Q.y / MagQ, Q.z / MagQ, Q.s / MagQ>;".

j'avoue ne pas comprendre du tout et justement sa dois etre l'élément de ma question suivante :

-le script fonctionne parfaitement, avec de la patience j'arrive a programmé le parcourt de mon mobile et au choix après de le faire en on-rez ou en touch-start ( j'ai pas encore testé avec le sensor ), le problème reste que si je passe le tout en rezzeur et que je décide d'installé le build dans une orientation différente en z , le mobile lui ne tien pas compte de la nouvelle orientation . je dois supprimé la normalisation ? ou il reste un moyen de normalisé en fonction de l'axe de rotation au rez du mobile ?

merci de vos réponses
Répondre

Connectés sur ce fil

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