Jump to content

Trying to make an object follower


Emma SecretSpy
 Share

You are about to reply to a thread that has been inactive for 2234 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

Hello,

Please, excuse my strange english...I'm a beginner in scripting and I use to modify already written scripts, hoping I will be able to learn things this way.

Well, I'm trying to make a caravan following a car (this car uses a basic physical car script).

I tested several possibilities, adapting the classical "AV follower" script: llSensor, llListen, llGetObjectDetails, physical with llMoveToTarget, "fast" functions, etc. But I couldn't obtain really satisfying results.

I tried to adapt the new function  llSetKeyframedMotion and I obtained this script:

 

vector offset = < -1.50, 0, 0>;  //1.5 meter behind my car center.
 
default
{
    state_entry()
    {
     
    llSleep(0.1);
  
       llSetTimerEvent(0.04); 
    }
    timer()
    {
        list det = llGetObjectDetails("my UUID car",[OBJECT_POS,OBJECT_ROT])
        //Get position and rotation
        vector pos   = llList2Vector(det,0);
        rotation rot = (rotation)llList2String(det,1);
       
        // Offset relative to the car. 
        vector carOffset = offset * rot;
 
        pos +=carOffset;       
 
         llSetKeyframedMotion([pos - llGetPos(), rot / llGetRot(), 0.1], []);
    }
}

 It works not so badly.

But I obtain this error message:  "Error: delta rotation at frame 0 contains a NaN, Inf, or is not a normalized rotation".

1. Is there a way to avoid this script error?

2. The movement of the caravan is nearly correct but it is a bit jerky. Could I add a buffer or something else, and how?

 

Thank you very much for your answers. I learned many things reading your messages in this forum.

Link to comment
Share on other sites

You're probably not going to be able to get rid of the jerky movement.  llSetKeyframedMotion is smooth, but you are running it within a timer event that has to trigger it at each time step, calculate a path, and set it moving again.  I suspect that the root of your real problem, though, is that you are running your timer event very fast (0.04 seconds) but the keyframed motion much slower (0.1 seconds). The timer keeps trying to interrupt the keyframed motion before it has finished.  You might be able to beat the problem by stopping the keyframed motion at the start of each time step, but I think you'll have better results if the two time scales are better matched. Try slowing down your timer.

  • Like 1
Link to comment
Share on other sites

Dear Rolig,

Thank you very much for your suggestion. I tried with 0.10 for the timer and the llSetKeyframedMotion and other values. The error message seems to appear less frequently, but still appears. It seems to appear when there is a rotation of the car (when it turns or goes up/down on the road).

Do you think using llSetKeyframedMotion is a good choice? What would be your suggestion to obtain the most acceptable movement for a following object like a caravan? Would you set it as physical? Would you use a sensor instead of a llGetObjectDetails? TY

Link to comment
Share on other sites

OK, I was wrong.  :=X    I got curious about your problem, so I tried it myself.  The solution has two parts.  First, the reason you are generating that error is that you need to apply a normalized rotation in the keyframed motion.  We had a question here about the same thing a couple of months ago.  I filed Void's verbal one line response away in my mind for "later."  So this is later, and I did the math.  Here's a quick function that normalizes any rotation:

rotation NormRot(rotation Q){    float MagQ = llSqrt(Q.x*Q.x + Q.y*Q.y +Q.z*Q.z + Q.s*Q.s);    Q.x = Q.x/MagQ;    Q.y = Q.y/MagQ;    Q.z = Q.z/MagQ;    Q.s = Q.s/MagQ;    return Q;}

 So, in the context of your problem, here's a follower that uses llKeyFramedMotion ....

rotation NormRot(rotation Q){    float MagQ = llSqrt(Q.x*Q.x + Q.y*Q.y +Q.z*Q.z + Q.s*Q.s);    Q.x = Q.x/MagQ;    Q.y = Q.y/MagQ;    Q.z = Q.z/MagQ;    Q.s = Q.s/MagQ;    return Q;}    integer gON;default{    state_entry()    {        llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_CONVEX]);     }        touch_start(integer total_number)    {        gON = !gON;        if (gON)        {            llSay(0,"Switch ON!");            llSensorRepeat("","91b39b5b-13b1-2517-273a-67360b842c02",SCRIPTED,10.0,PI,0.1); //Following my scripted vehicle        }        else        {            llSensorRemove();        }    }        sensor(integer num)    {        llSetKeyframedMotion([(llDetectedPos(0) - llGetPos()) + <-1.0,0.0,0.2>*llDetectedRot(0), NormRot(llDetectedRot(0)/llGetRot()),0.11],[]);    }}

 I am using the same general formulation that you are for setting up llKeyFramedMotion itself, except that I am calling that normalizing function to get the rotation.  ( I am also using llDetectedPos and llDetectedRot instead of going the long route with llGetObjectDetails).

The second part of the solution is about getting rid of the jerkiness.  As it turns out, that's just a matter of setting the time in llKeyFramedMotion just slightly longer than the time step in your timer (or in my case, in llSensorRepeat).  If both of them, in turn are faster than the speed of whatever you are following, the motion is smooth.  For the vehicle I was following as a test, I got great results by running llSensorRepeat at 0.1 seconds and llKeyFramedMotion at 0.11.

  • Like 1
Link to comment
Share on other sites

Iit would appear that the minimum time step for llSetKeyframedMotion is 1/9 of a second now, not 1/10 second as originally implemented.

This changed about a week ago.   They seem to have fixed the prim drift at the same time.

A number of my animations stopped working and I had to edit them.

use .111112 if you are entering it as a constant,  values from .100000 to .111111 won't work anymore, it gets rounded down now to the next lower 1/45 of a second.   This has fixed the prim drift I was experiencing previously.

 

 

  • Like 1
Link to comment
Share on other sites

Thank you Rufus (and Rolig again, of course),

Yes, the server of the region where I was has been updated and I have had to make the modification. If I hadn't read your message before, I would have understood nothing.

May I have another question? Is there a way to dissociate the position and the rotation in the llSetKeyframedMotion command?

I mean when the car  or engine turns, the caravan turns immediately too and the effect doesn't look so natural. Would it be possible to add a delay of 1 or 2 seconds before the follower rotates, keeping the same value for the position and the offset?

0.111112 for the timer is perfect for the position+offset because of the possible variations of the speed: if I increase the timer and the offset values to obtain a delay for the rotation, I lose precision.

Using the Rolig's code, we would have something like (obviously I know it doesn't work this way) :

 

llSetKeyframedMotion([(llDetectedPos(0) - llGetPos()) + <-1.0,0.0,0.2>*llDetectedRot(0), 0.11112],[]);// ANDllSetKeyframedMotion([NormRot(llDetectedRot(0)/llGetRot()),2],[]);

 

 

 

Link to comment
Share on other sites

You can certainly separate them.  Your examples should work if you rewrite them as

llSetKeyframedMotion([(llDetectedPos(0) - llGetPos()) + <-1.0,0.0,0.2>*llDetectedRot(0), 0.11112],
[KFM_DATA,KFM_TRANSLATION]);// ANDllSetKeyframedMotion([NormRot(llDetectedRot(0)/llGetRot()),2.0],[KFM_DATA,KFM_ROTATION]);

Whether they would achieve the effect you want is another matter, but you could experiment with various values and find out. 

 

Link to comment
Share on other sites

The problem is that you can't run two animations at once, so the shorter one (the translation) can't fire again until the longer one has finished.  My guess is that to make it work, you'll have to set their times nearer to the same and lengthen the time of your SensorRepeat.  That will mess up the smoothness of your follower, though.  There's got to be a balance in there somewhere, but it's going to take a lot of experimentation.

Link to comment
Share on other sites

Hmmm... Lucinda is right concerning position, Emma.  Unlike llSetPos, llSetRegionPos doesn't have a 0.2 second delay, so you could reset your follower's position at each time step with a call to

llSetRegionPos( llDetectedPos(0) + offset * llDetectedRot(0) );

Then just take the translation out of your keyframed motion, leaving it to deal with the rotation alone.  Without the 0.2 second delay, the follower shouldn't be choppy, and the keyframed motion will keep the rotation smooth, which was your goal.  It will still take some fiddling, but you might make it work.

Link to comment
Share on other sites

Lucinda and Rolig,

Thanks for the suggestion: it was a good idea, but translation and rotation don't work together ("Cannot use a script to move a linkset while it is playing an animation. Stop the animation first.").

Anyway, the following movement (with translation only) is very jerky, this way...

Link to comment
Share on other sites

I make vehicles, but vehicles of war, I make guided missiles, they do a very good job of following me no matter how I try to dodge and twist to escape them, I would not do it the way you are doing it, I would turn both objects into vehicles and have the lead transmitting its vehicle state to the slave, I would use llRegionSayTo to transmit the key data to the slave vehicle, and use llRegionSetPos(none physical) you quickly put it in place should it change to much, what you seem to have is a none physical object following a physical object, in my world the none physical object is of no use cos how will it fit in a war game were it can be blown up or knocked over, so it is something I would never do, I do know that with my missile the math's gets complex plotting paths, I feel that would be a nightmare to paste here as it would lead to a 100 more questions and I don't have the time.

 

You can set the physical state to false do the setregionpos then set the state true, never use instructions with a delay when doing this or it will make the vehicle jerk, but if you use moments when the lead is turning some jerks never get noticed,

I don't use any form of setpos instruction in the missiles, they are pure vehicles and use sensor to find their targets and steer towards them, they have their own set of flying stats so to simulate the fins they have and turning angle, their speed and acceleration are the same according to the engine they have, now that castray is working for all things again they will have that replace sensor, well I hope, I have to see if my ideas about using cast ray will work, in scan patterns.

But I feel what you want is in fact quite complex and will need a good understanding of the available instructions, sorry that I don't have the time to help, but my knowledge is limited to what I make, were the helpers here have a wider scope than me, but you are asking them to do a bit more than they normally do here.

Link to comment
Share on other sites

Hello Lucinda,

Thank you for your suggestions. Anyway I'll test several possibilities, including physical state. I haven't a scientific formation and I 'm just a beginner in scripting. But I learn lots of things here, reading messages like Rolig's ones and trying things.

It is not so easy to find LSL documentation or experts in my native language, that is why I came here.

"but you are asking them to do a bit more than they normally do here.": I am very conscious of that and grateful for the time they spend here. What Rolig found about rotation normalisation in this discussion is very important and I'm sure it will be useful for everyone.

About the dissociation translation/rotation we discussed yesterday: I could make it work using the SensorRepeat for the translation and, independently, a timer, where I put the rotation command.

 

Link to comment
Share on other sites

What I think you're trying to do is to get the "follower" to execute the same turns at the same places as the thing it's following, like railcars behind a locomotive, and as you've seen, that's different from merely trying to stay behind the leader.  

The follower, then, is trying to match the history of the leader's position and orientation, delayed according to speed so as to maintain a (more or less) constant separation.

I think Lucinda's is a good suggestion to have the leader share its path information to the followers, instead of the followers having to discover it by watching what the leader did.  That will save on sensor events or llGetObjectDetail calls.

What approach you use to move the followers is mostly a matter of convenience and efficiency.  I think you can do it with keyframed animation, basic physics, or vehicle physics.

 (Passing observation: keyframed animation doesn't seem to be as huge of an efficiency win as one might wish, if it's getting called multiple times a second.  Where it really excels is for looped or one-time ballistic motion, where the script doesn't even need to remain in the animated object once the motion starts.)

Link to comment
Share on other sites

Right, Qie.  Emma's original question posed an interesting challenge, using the combination of a fast-repeating sensor and the new llKeyframedMotion function to create a smooth follower.  It's a nice idea, and it attracted me because it needed the extra touch of normalizing the rotations in order to work properly.  Adding her latest requirement puts it into a different realm.  As Emma noticed, it means that the follower has to delay its movements in order to follow the same path as its target.  She's essentially designing a frieght train that doesn't need tracks but still needs to look like it has them.

Lucinda's suggestion has merit.  I have little or no interest in missles, so I'd need to invent the guidance technology from scratch.  In rough form, though, you're right. It's a matter of having the follower keep track of where the target used to be, and then heading for that same spot a second or two later. I think I'd still use keyframed motion to move the follower, simply because I think you'd get smoother action that way, but that's something to experiment with.  It's never going to be perfect, but then a RL frieght train isn't either.  The cars bump back and forth as the engine changes speed and the cars don't know it yet.  That's realism for you.

Link to comment
Share on other sites

Hi, I think what you are trying to do is hard, it is worst than a train, because when the car turns so the pivot point rotates away from the center of the two, so that just adds to the nightmare of plotting the course, a missile is easy as such because it want to get just ahead of me and don't have to worry about its nose being on a pivot point, that is the bit I see as hard, as rolin said its a whole mass of rotations and no one likes those, I wish you all luck, I think if it was easy we would see lorry's and trailers all over with trains to.

 

Just had a thought, what about wearing the trailer and making the pivot point the root of it, you are fixed in the car, so you can make sure the root is always over the pivot point, then rotate the root opposite to the rotation of the car, then smooth out the rotation as the car front wheels face forward.

Link to comment
Share on other sites

  • 6 years later...
You are about to reply to a thread that has been inactive for 2234 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...