Jump to content

Catmull Rom or Bezier curves in game play animal movement


VirtualKitten
 Share

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

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

Recommended Posts

Well nothing still works I ported main bits into a cube and cut out what was not needed from my creation just the current move bits  if you put it in a long box  it wont do what you said it would :
 

integer target_wander_id= 0;
integer on_ground_not_flying =0;
vector WANDER_RANGE = <20.0,20.0,10.0>; // Set ranges to wander
vector iPos;
vector pos;
vector vLastRelPos;
float TARGET_AFFINITY = .4; // How fast will the primitive try to reach  the 
list lCoordinate=[];
rotation lastRot;
vector my_home; 
integer TYPE_FLIGHT;
float timer_wander;
vector nex_pos;
float FUDGE = 0.1; // random delay in flight speed 
float SPEED = 1.0; // speed of flight.
integer target; 
Debug( string s )
{
   llSetText( s, <1,1,1>, 1.0 );
   //llSetText( "", <1,1,1>, 1.0 );
}
rotation NormRot(rotation Q)
{
    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>;
}
vector range = < 5.0, 5.0, 5.0 >; 
rotation homeRot;
vector LEFT=< 0.0, 1.0, 0.0 >;
rotation refFrame=<0,0,-0.71,0.71>; 
vector P1;
vector P2;
vector P3;
vector Q1;
vector Q2;
vector Q3;
integer b_i=0;
integer liN = 24;
rotation newrot =ZERO_ROTATION;
vector randomP()
{
    return llGetPos() + < WANDER_RANGE.x*(llFrand( 2.0)-1.0), WANDER_RANGE.y*(llFrand( 2.0)-1.0), WANDER_RANGE.z*(llFrand( 2.0)-1.0) > * homeRot;
}

coefisFirst()
{
    P0 = llGetPos();
    Po0 = P0;
    P3 = randomP();
    P2 = randomP();
    P1 = randomP();
    Po1 = P1;
    Q1 = 3.0*P1-3.0*P0;
    Q2 = 3.0*P0-6.0*P1+3.0*P2;
    Q3 = 3.0*P1-P0+P3-3.0*P2;

}
coefisNext()
{
    P0 = P3;
    P1 = 2.0*P3-P2;
    P3 = randomP();
    P2 = randomP();
    Q1 = 3.0*P1-3.0*P0;
    Q2 = 3.0*P0-6.0*P1+3.0*P2;
    Q3 = 3.0*P1-P0+P3-3.0*P2;
    
}
vector Bez( float x ) { return P0 + (Q1 + (Q2 + Q3*x)*x)*x; }
vector dBez( float x ) { return Q1 + (2.0*Q2 + 3.0*Q3*x)*x; }

rotation Vec2Rot( vector FWD )
{
    
    FWD = llVecNorm( FWD );
    vector UP = < 0.0, 0.0, 1.0 >;
    if ( llFabs(FWD.z) < 1.0 ) LEFT = llVecNorm(UP%FWD);
    UP = llVecNorm(FWD%LEFT);
    return refFrame*llAxes2Rot(FWD, LEFT, UP);
}

integer __llTargetRemove(integer _id){
    llTargetRemove(_id);
    return 0;
}
integer  checkInside2(vector bottomLeftCorner, vector topRightBack, vector pos) 
{
    if (topRightBack == ZERO_VECTOR ||
    bottomLeftCorner == ZERO_VECTOR ||
    pos.x < bottomLeftCorner.x ||
        pos.y < bottomLeftCorner.y ||
        pos.x > topRightBack.x ||
        pos.y > topRightBack.y ||
        pos.z > topRightBack.z )  {
            return FALSE; // If weare outside area
    }
    return TRUE;
}

vector Po0;
vector Po1;
vector P0;

integer _llObtainLinkFromKey(key l_key)
{
    integer l_i =  llGetNumberOfPrims();
    if(llGetLinkKey(l_i ) == l_key) return l_i;
    for(; l_i--;) if(llGetLinkKey(l_i ) == l_key) return l_i;
    return -1;
} 
 
vector clipRegion(vector bot, vector top, vector pos)
{
    if (pos.x < bot.x) pos.x = bot.x;
    else if (pos.x > top.x) pos.x = top.x;
    if (pos.y < bot.y) pos.y = bot.y;
    else if (pos.y > top.y) pos.y = top.y;
    if (pos.z < bot.z) pos.z = bot.z;
    else if (pos.z > top.z) pos.z = top.z;
    return pos;
}
vector nextCoordinates(integer p_TYPE) {
    // float driftRange = llFrand(MOVEMENT_RANGE);
    // float circle_radius = 5.0;
    // float a = llFrand(TWO_PI);
    // float b = llFrand(TWO_PI);
    // float c = llFrand(PI);
   Debug("nextCoordinates");
    // if(TYPE == 2) return <iPos.x + driftRange, iPos.y + llFrand(MOVEMENT_RANGE), iPos.z>;
    //if(TYPE == 4) return <iPos.x + driftRange * llCos(a), iPos.y + driftRange * llSin(b), iPos.z>;
    //  if(TYPE == 8) return iPos + <driftRange * llCos(a) * llCos(b), driftRange * llCos(a) * llSin(b), driftRange * llSin(a)>;
   // if(p_TYPE == 9) {
         if (b_i == liN || b_i == 0) { b_i = 0;  coefisFirst();}
         iPos = Bez( b_i/liN); 
         newrot = Vec2Rot(dBez( b_i/liN));
         b_i++;
         
     //}  
 llInstantMessage(llGetOwner(),"ipos:"+(string)iPos+", newrot:"+(string)newrot+", TYPE:" +(string)p_TYPE+" b_i:"+(string)b_i);
    return iPos;
}

integer __loadCoordinates(vector l_pos ,vector l_dest,rotation l_rot, float time , integer target) 
{
            //Debug("Load Points...");
           llInstantMessage(llGetOwner(),"lpos:"+(string)l_pos+", lDest:"+(string)l_dest);
            // time =  distance/velocity
            
             time = (float)llVecDist(l_pos,(l_pos+l_dest))/TARGET_AFFINITY; 
             if(time < 0.2) time = .3;
             lCoordinate = [];
             lCoordinate +=l_dest; 
             lCoordinate += l_rot; // * any new rot relative to current position.
             lCoordinate +=time;
             pos =  l_pos+l_dest;
             vLastRelPos =pos;
             lastRot = llGetRot();
             //iStartTimer = TRUE;
             target = __llTargetRemove((integer)target);
             llSetKeyframedMotion(lCoordinate, [KFM_DATA, KFM_TRANSLATION|KFM_ROTATION, KFM_MODE, KFM_FORWARD]);
            //iStartTimer = FALSE;
       
             return  llTarget(pos, 50.0);
}
_llWanderWithinKeyframe (vector home,  vector range, list c) {
    pos = llGetPos();
    iPos = llGetPos();

    list TYPE = [9] ; // ,16,32,64,128,126];
    integer vAreaParcelsqm = llList2Integer(llGetParcelDetails(iPos,[PARCEL_DETAILS_AREA]),0);
    vector area = < vAreaParcelsqm -.25, vAreaParcelsqm -.25,vAreaParcelsqm -.25>;
    vector bot = my_home-WANDER_RANGE/2.0;
    vector top = my_home+WANDER_RANGE/2.0;
    //llInstantMessage(llGetOwner(),"bot:"+(string)bot+"top:"+(string)top);
    //   if(TYPE_COUNT++ > 1) { TYPE_COUNT = 0; TYPE_FLIGHT =               
    //  (integer)(llFrand(7.0)); iPos = llGetPos();} 
   TYPE_FLIGHT = 0;
   if( TYPE_FLIGHT == 10) {TYPE_FLIGHT  == 0; iPos = llGetPos();}
    integer i = 20;
    //timer_wander = llGetUnixTime();
    do {
   
        //Debug("_llWanderWithinKeyframe:Process point:"+(string)nex_pos);
        nex_pos = clipRegion(bot,top,nextCoordinates(llList2Integer(TYPE,TYPE_FLIGHT) )); 
    }  while(checkInside2(bot,top,nex_pos) == FALSE && i-- >0);
      
    if(nex_pos != ZERO_VECTOR && i!=0) {
         llInstantMessage(llGetOwner(),"_llWanderWithinKeyframe: Moving ipos: "+(string)iPos+"next"+ (string)nex_pos); 
         if(TYPE_FLIGHT != 9)  newrot = llGetRot();
         target_wander_id = __loadCoordinates(iPos,(nex_pos-iPos),newrot, llFrand(FUDGE)+ (nex_pos.z)/SPEED,target_wander_id);
        
    }
}
default
{
    state_entry()
    {
         pos = llGetPos();
         iPos = pos;
         my_home = llGetPos();
         llSetLinkPrimitiveParamsFast(LINK_THIS,
    [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_CONVEX]);
    }

    touch_start(integer total_number)
    {
        integer i = 10;
        do {
            _llWanderWithinKeyframe (llGetPos(),WANDER_RANGE, []);
        }  while(i-- > 0);
    }
   at_target(integer tnum, vector targetpos, vector ourpos) {
        if(tnum == target_wander_id) {   
             //iStartTimer = FALSE;
             target_wander_id = __llTargetRemove(target_wander_id);
         }
    }
    
    
}

 

Link to comment
Share on other sites

Just playing with this in a sandbox, just before the call to llSetKeyframedMotion I chatted out the list lCoordinate which you are passing to llSetKeyframedmotion and it consists of a Zero Vector, a Zero rotation, and a time of 0.3 seconds, so no movement is going to occur.

You need to debug what you are feeding into the list lCoordinate.

Here is my suggestion:

Remove all diagnostic output except the immediate feed to the keyframedMotion, lCoordinate.

If you see Zero vector and zero rotation., move the diagnostic output backwards in the sequence of statements to check what you are passing into that routine.  Examine the positions and rotations , which should be non-zero if any movement is to occur.

Keep doing this until you reach the point where you are outputting actual changes to position and rotation, then go forwards again to see where they are being lost.

You have several possible causes such as the routine that tries to clip the generated values to keep them inside a region boundary.

 

If that is too hard to contemplate, then go in the other direction: Start where you generate your next position and look to see why this different position then gets changed back to  zero vector

 

Either way should gradually lead you to where you are losing the calculated values.

 

(I also think that with keyframedmotion you might be better off using moving_end rather than at_target? I've never used targets with KFM< only with llMoveto and RotLookat)

Edited by Profaitchikenz Haiku
Link to comment
Share on other sites

I see that you are not using ownerSay for your diagnostics but llInstantMessage in several places. This might cause you a few problems:

From the wiki

llInstantMessage

  • This function causes the script to sleep for 2.0 seconds.
  • If the specified user is logged in, message will appear in the chat window and will not logged by the InstantMessage logging facility.
  • If messages are sent to the same user by the same object within about 65 seconds, they will be bundled together in a single email

Messages longer than 1175 bytes will be truncated to 1175 bytes

 

Using llOwnerSay is going to be far quicker

Link to comment
Share on other sites

15 minutes ago, VirtualKitten said:

Prof its the same bits of code in a call routine instead of the unstable add to list routine in her script and yours  .The other routines work without this fine so it must be the curve creation bit 

If you know where it's going wrong you're 90% of the way to fixing it!

My suggestion, which may or may not be taken seriously, is to simplify this, 

Abandon all the wander-within, keyframed motion, constrain within parcel and simply write a small routine that generates a series of points.

Make the cube move to each point.

When you are happy that the cube is moving to each point, add keyframed motion and glide from each point using the delta values for positions and rotations.

When you are happy that it i working, add in the constrain to region/parcel limits

After that, add in flight types, etc.

I started to see if I could make sense of the script but it is far too complicated to debug by just reading, and produces faar too much chatter to see anything in the stream of messages.

 

Mullah Nasrudin was discovered crawling around on his hands and knees in the road outside his house.

Onlookers asked him "What are you doing?"

He replied "I lost my keys".

They got down on their hands and knees to help him, and one of them asked "Where were you when you dropped them?"

He replied "I was indoors"

The same one asked him "Then why are you looking for them out here?"

He replied "It's too dark to see anything inside"

 

Link to comment
Share on other sites

Two pointers to help you. 

First, you are starting your b_i counter from 0, instead of 1 as I did. What this means is that the fractions of the bezier offsets P1 to P3 and Q1 to Q3 that should be added incrementally to the starting positions will be zero and the first points you calculate are therefore just your starting points, so no movement will occur

 

vector Bez( float x ) { return P0 + (Q1 + (Q2 + Q3*x)*x)*x; }
vector dBez( float x ) { return Q1 + (2.0*Q2 + 3.0*Q3*x)*x; }

// from nextCoordinates

        if (b_i == liN || b_i == 0) { b_i = 0;  coefisFirst();}
         iPos = Bez( b_i/liN); // when b_i = 0 iPos = P0
         newrot = Vec2Rot(dBez( b_i/liN));
         b_i++;

So when b_i starts at 0 iPos is just the starting positon.

Later on in the routine __llwanderWithinKeyfame, you calculate nex_pos with a call to clipRegion on the result of calling nextCoordinnates, all well and good.

I am seeing a value in nex_pos once b_i has incremented from zero that is different to the starting position, but then, what you pass to __loadCordinates to actually do the Keyframed motion are two vectors of identical value, iPos and nex_pos - iPos, so there will be a zero vector result and no keyframed motion

         target_wander_id = __loadCoordinates(iPos,(nex_pos-iPos),newrot, llFrand(FUDGE)+ (nex_pos.z)/SPEED,target_wander_id);

 

And I think the reason iPos has changed from what it should be, the current position from which you want to move to nex_pos is because although iPos is a global, you have assigned a value to it as the return from a function

 

vector nextCoordinates(integer p_TYPE) {
    // float driftRange = llFrand(MOVEMENT_RANGE);
    // float circle_radius = 5.0;
    // float a = llFrand(TWO_PI);
    // float b = llFrand(TWO_PI);
    // float c = llFrand(PI);
   Debug("nextCoordinates");
    // if(TYPE == 2) return <iPos.x + driftRange, iPos.y + llFrand(MOVEMENT_RANGE), iPos.z>;
    //if(TYPE == 4) return <iPos.x + driftRange * llCos(a), iPos.y + driftRange * llSin(b), iPos.z>;
    //  if(TYPE == 8) return iPos + <driftRange * llCos(a) * llCos(b), driftRange * llCos(a) * llSin(b), driftRange * llSin(a)>;
   // if(p_TYPE == 9) {
         if (b_i == liN || b_i == 0) { b_i = 0;  coefisFirst();}
         iPos = Bez( b_i/liN); 
         newrot = Vec2Rot(dBez( b_i/liN));
         b_i++;
         
     //}  
 llInstantMessage(llGetOwner(),"ipos:"+(string)iPos+", newrot:"+(string)newrot+", TYPE:" +(string)p_TYPE+" b_i:"+(string)b_i);
    return iPos;
}

 

inside that function I think you need to have a local vector variable __localVectorIposSubstitute which gets the return value from bez and that is the return value 

That assignment is made inside the do loop in _llwanderWithinKeyframe's do loop

 

   do {
   
        //Debug("_llWanderWithinKeyframe:Process point:"+(string)nex_pos);
        nex_pos = clipRegion(bot,top,nextCoordinates(llList2Integer(TYPE,TYPE_FLIGHT) )); 
    }  while(checkInside2(bot,top,nex_pos) == FALSE && i-- >0);

So the only time you will ever get different values between iPos and nex_pos is if the region clip routine changes anything. At all other times, you will be generating KeyframedMotion vector delta values of <0.0,0.0,0.0> and it is no surprise that nothing moves.

(To clarify, I believe you need to keep iPos as where the prim is currently, calculate nexPos as where it will be on the bezier curve subject to region clipping, and then the value nex_pos-iPos you pass to the keyframed motion wrapper routine should work. That means the assignment of Bez(b_i/liN) must not go to IPos, but via the function return to nex_pos.. subject to region clipping)

 

Pro-tip: Function return values must be local to the function, to avoid unexpected effects

 

After some fiddling in a sandbox I did manage to get some movement.

Edited by Profaitchikenz Haiku
Link to comment
Share on other sites

Hi prof ,I will take another look at my code the reason is is assigning Ipos is that it should have already moved to new position by KFM event loop after and returning to __llWanderWithin  You may be correct with regard start value 0 or 1 . Global versus local variables seem to use memory different in  second life  for example local variables seem more able to use more memory .in a script .I don't know why this is but it can be observed in 800lines of code.

Hugs

 

Link to comment
Share on other sites

Profaitchikenz Haiku

As you can see the code steps and printout to iteration but moved once while printing  also noted Ipos was being returned from nextCoordinates  not newrot: 

 

 if (b_i == liN || b_i == 1) { b_i = 1;  coefisFirst();}
         iPos = Bez( b_i/liN); 
         newrot = Vec2Rot(dBez( b_i/liN));
         iPos = (dBez( b_i/liN));
         b_i++;

}

 

I also tried 

         if (b_i == liN || b_i == 1) { b_i = 1;  coefisFirst();}
         iPos = Bez( b_i/liN); 
         newrot = Vec2Rot(dBez( b_i/liN));
         newpos = (dBez( b_i/liN));
         b_i++;

 

 

No on its travels it goes off sim
5733cc62a33a6a8253ff8eca295657b5.png

 

Hugs D

Edited by VirtualKitten
Added Image
Link to comment
Share on other sites

Yes, I also gt more vertical movement than horizontal but I didn't have a lot of time. Once I get the region monitoring project sorted I'll have another look.

Regarding the vertical movement, chat out the two vectors frrom which you derive the KFM delta, which are the current position and the result of clipping the generated bezier position to region coordinates, and look at the delta produced. Is all the difference in the Z coordinates?

Link to comment
Share on other sites

Hmm yep it doesn't like the sim border also it would be nice for it to go different arc rotated if its edge  collides with something  I can detect objects with  my routine in creature but presumable if i rotate this 90 degrees it will still keep trying to go in that direction ?

 

float _GetBoundingBox(key box_key) {
    
     if(box_key != NULL_KEY) {
         list box = llGetBoundingBox( box_key); 
         vector size = llList2Vector(box, 1) * llGetRot() - llList2Vector(box, 0) * llGetRot();
         if (llAbs(llRound(size.x)) < llAbs(llRound(size.y))) {
            float temp = size.y;
            size.y = size.x;
            size.x = temp;
        }
        return llAbs(llRound(size.z));
     }
     return -1;
}

float _llGetBoundaryUsingCastRay(string raytype, float width){
     list ray=[];
     if(raytype=="-y") { ray = llCastRay(llGetPos()+<-(width/2),0.0,0.0>,llGetPos() + <width/2, -50.0, 0.0>,[RC_MAX_HITS, 5]);
     } else   if(raytype=="-x") { ray = llCastRay(llGetPos()+<0.0,-(width/2),0.0>, llGetPos() + <-50.0, (width/2), 0.0>,[RC_MAX_HITS, 5]);
     } else   if(raytype=="x") { ray = llCastRay(llGetPos()+<0.0,-(width/2),0.0>, llGetPos() + <50.0,(width/2), 0.0>,[RC_MAX_HITS, 5]);
     } else   if(raytype=="y") { ray = llCastRay(llGetPos()+<-(width/2),0.0,0.0>, llGetPos() + <(width/2), 50.0, 0.0>,[RC_MAX_HITS, 5]);
     } else return -1;
     // We have a Ray
    //llOwnerSay((string)ray + " raytype = " + raytype);
     vector mypos = llGetPos();
     integer i=0;
    
     integer position;
     mypos = llGetPos();
     do {
           key lkID =  llList2Key(ray, i);
          // vector i_pos =    llList2Vector(ray,i+1);
           if(llSubStringIndex(raytype, "x")!=-1) {
               if((integer)pos.x != (integer)mypos.x ) {
                  position= i+1;
                 i = llGetListLength(ray) - 1;
               };
           } else if(llSubStringIndex(raytype, "y")!=-1) {
                 if((integer)pos.y != (integer)mypos.y ) {
                  position= i+1;
                 i = llGetListLength(ray) - 1;
               }; 
           }
           i+=2;
     } while(i<=llGetListLength(ray) - 1);
     vector collision_pos = llList2Vector(ray,position);

     if(llSubStringIndex(raytype, "-y")!=-1 ){ return (integer)llFabs((mypos.y - collision_pos.y));
     } else if(llSubStringIndex(raytype, "-x")!=-1) { return (integer)llFabs((mypos.x-collision_pos.x));
     } else if(llSubStringIndex(raytype, "x")!=-1) {return (integer)llFabs((collision_pos.x-mypos.x ));
     } else if(llSubStringIndex(raytype, "y")!=-1) { return (integer)llFabs((collision_pos.y -mypos.y));
     } else return -1;
}
integer doCheckFloorcollision_key(key k) {
     Debug("Check Collision with Floor");
     float width = 4;
     list ray = llCastRay(llGetPos()+<-(width/2),0.0,0.0>, llGetPos() + <(width/2), 50.0, 0.0>,[RC_MAX_HITS, 5]);
     vector mypos = llGetPos();
     integer i=0; 
     integer position;
     do {
           key lkID =  llList2Key(ray, i);
           vector ir_pos =    llList2Vector(ray,i+1);
           if((integer)ir_pos.y != (integer)mypos.y ) {
              position= i+1;
              i = llGetListLength(ray) - 1;
           }
           i+=2;
     } while(i<=llGetListLength(ray) - 1);
     vector collision_pos = llList2Vector(ray,position);
     if(llList2Key(ray,i) ==  k) return FALSE; else return TRUE;
}
float DoCheckSurrounding(string c) {
   if(c=="UP") {
        float _a = _llGetBoundaryUsingCastRay("-y", 1.2);
        Debug(" Upper Boundary @ " +(string)_a);
        if(_a >10.0)         return _a; 
        else return -1;
    }
    return -1;
}
integer __llTargetRemove(integer _id){
    llTargetRemove(_id);
    return 0;
}

Edited by VirtualKitten
Added code
Link to comment
Share on other sites

Thanks what would be the right method to reverse the curve from a collision using my code please which will detect collision. I presume i could run doCheckFloorcollision_key(key k)  to detect crash into floor  Could I use _llGetBoundaryUsingCastRay(string raytype, float width) to get alternate direction notification to reverse curve in different direction at a reflected incident of impact like a ball would rebound

 

I think I would need to rotate refFrame  and Ipos and call Coefisfirst() again but how can I get incidence of refraction and add it to rotation in refFrame and Ipos?

like 

do {

         if (b_i == liN || b_i == 1) { b_i = 1;  coefisFirst();} 
         newrot = Vec2Rot(dBez( b_i/liN));
         newpos = (dBez( b_i/liN));
         b_i++;

         if(collision()) {

                  b_i = 1;  

                  // reverse reflected incidence from perpendicular of ray angle  in iPos and refFrame?

                 coefisFirst();

} until(!collision)

Hugs D

 

Edited by VirtualKitten
Link to comment
Share on other sites

Here is a version of your routine that does actually make a move. I commented out targets coding through the code because it wasn't being used in a comprehensible way: (a target was being set then removed before even calling the routine that was going to try and move to that target), and also there is currently no means at the at_target event of stepping through the parts of the bezier curve. Instead, I used moving_end.

However, it won't work in the way you want because at the moment, you don''t go through each incremental part of the calculated bezier curves from one to the next.

I can't see a quick and easy easy for me to add a kick-off in moving_end to the next point on the bezier curve because you re using local variable-controlled do_loops inside the touch_event, and no obvious coding anywhere else to increment b_i from 1 to liN, which is what you must do to get all the points along the bezier

 

As I read your code at present, you call nextCoordinates to generate a bezier point according to global b_i

b_i needs to increment from 1 to liN to generate a set of points along the bezier

Therefore each time you finish a short move you need somewhere to increment b_i, call next_coordinates again, and pass the new coordinates back into __loadCoordinates to then make the next keyframed move.

I think you need to make something like a flow chart to work out where you are doing the important calculation parts and in what order the routines are to be called.

But hopefully the fact that you can see this code actually working and moving a prim will inspire you to rework the code.

 

integer target_wander_id= 0;
integer on_ground_not_flying =0;
vector WANDER_RANGE = <20.0,20.0,0.0>; // I HAVE SET Z to 0.0 FOR TESTING ON  THE GROUND Set ranges to wander
vector iPos;
vector pos;
vector vLastRelPos;
float TARGET_AFFINITY = .4; // How fast will the primitive try to reach  the 
list lCoordinate=[];
rotation lastRot;
vector my_home; 
integer TYPE_FLIGHT;
float timer_wander;
vector nex_pos;
float FUDGE = 0.1; // random delay in flight speed 
float SPEED = 1.0; // speed of flight.
//integer target; 

Dout( string s)
{
    llOwnerSay(s);
}
Debug( string s )
{
   llSetText( s, <1,1,1>, 1.0 );
   //llSetText( "", <1,1,1>, 1.0 );
}
rotation NormRot(rotation Q)
{
    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>;
}
vector range = < 5.0, 5.0, 5.0 >; 
rotation homeRot;
vector LEFT=< 0.0, 1.0, 0.0 >;
rotation refFrame=<0,0,-0.71,0.71>; 
vector P1;
vector P2;
vector P3;
vector Q1;
vector Q2;
vector Q3;
integer b_i=0;
integer liN = 5; // was 24
rotation newrot =ZERO_ROTATION;

vector randomP()
{
    return llGetPos() + < WANDER_RANGE.x*(llFrand( 2.0)-1.0), WANDER_RANGE.y*(llFrand( 2.0)-1.0), WANDER_RANGE.z*(llFrand( 2.0)-1.0) > * homeRot;
}

coefisFirst()
{
    P0 = llGetPos();
    Po0 = P0; // why?
    P3 = randomP();
    P2 = randomP();
    P1 = randomP();
    Po1 = P1; // why?
    Q1 = 3.0*P1-3.0*P0;
    Q2 = 3.0*P0-6.0*P1+3.0*P2;
    Q3 = 3.0*P1-P0+P3-3.0*P2;
    Dout("coefisFirst P1 " + (string) P1 + " P2 " + (string) P2 + " P3 " + (string) P3);
    Dout(" and Q1 " + (string) Q1 + " Q2 " + (string) Q2 + " Q3 " + (string) Q3);
}
coefisNext()
{
    P0 = P3;
    P1 = 2.0*P3-P2;
    P3 = randomP();
    P2 = randomP();
    Q1 = 3.0*P1-3.0*P0;
    Q2 = 3.0*P0-6.0*P1+3.0*P2;
    Q3 = 3.0*P1-P0+P3-3.0*P2;
    
}
vector Bez( float x ) {
    // Dout("Bez with x = " + (string) x);
     return P0 + (Q1 + (Q2 + Q3*x)*x)*x; } // note if you pass in 0.0 you will get back P0 !!!!
vector dBez( float x ) {
    // Dout("dBez with x = " + (string) x);
    return Q1 + (2.0*Q2 + 3.0*Q3*x)*x; } // note if you pass in 0.0 you will get back Q1 !!!

rotation Vec2Rot( vector FWD )
{
    
    FWD = llVecNorm( FWD );
    vector UP = < 0.0, 0.0, 1.0 >;
    if ( llFabs(FWD.z) < 1.0 ) LEFT = llVecNorm(UP%FWD);
    UP = llVecNorm(FWD%LEFT);
    return refFrame*llAxes2Rot(FWD, LEFT, UP);
}

//integer __llTargetRemove(integer _id){
//    llTargetRemove(_id);
//    return 0;
//}
integer  checkInside2(vector bottomLeftCorner, vector topRightBack, vector pos) 
{
    if (topRightBack == ZERO_VECTOR ||
    bottomLeftCorner == ZERO_VECTOR ||
    pos.x < bottomLeftCorner.x ||
        pos.y < bottomLeftCorner.y ||
        pos.x > topRightBack.x ||
        pos.y > topRightBack.y ||
        pos.z > topRightBack.z )  {
            return FALSE; // If weare outside area
    }
    return TRUE;
}

vector Po0;
vector Po1;
vector P0;

integer _llObtainLinkFromKey(key l_key)
{
    integer l_i =  llGetNumberOfPrims();
    if(llGetLinkKey(l_i ) == l_key) return l_i;
    for(; l_i--;) if(llGetLinkKey(l_i ) == l_key) return l_i;
    return -1;
} 
 
vector clipRegion(vector bot, vector top, vector pos)
{
    Dout("clipRegion bot " + (string) bot + " top " + (string) top + " position " + (string) pos);
    if (pos.x < bot.x) pos.x = bot.x;
    else if (pos.x > top.x) pos.x = top.x;
    if (pos.y < bot.y) pos.y = bot.y;
    else if (pos.y > top.y) pos.y = top.y;
    if (pos.z < bot.z) pos.z = bot.z;
    else if (pos.z > top.z) pos.z = top.z;
    Dout("clipRegion result is " + (string) pos);  
    return pos;
}
vector nextCoordinates(integer p_TYPE) {

    vector myNewPos;
   Dout("nextCoordinates b_i = " + (string) b_i);
         if (b_i == liN || b_i == 0) { b_i = 1;  coefisFirst();}    // START FROM 1 not 0
         myNewPos = Bez( b_i/ (float) liN); // trivial point but it is a float in my one-shot
         newrot = Vec2Rot(dBez( b_i/ (float) liN));
         b_i++;
          
        Dout("nextCoordinates result myNewPos:"+(string)myNewPos+", newrot:"+(string)newrot+", TYPE:" +(string)p_TYPE+" b_i:"+(string)b_i);
    return myNewPos;
}

integer __loadCoordinates(vector l_pos ,vector l_dest,rotation l_rot, float time , integer target) 
{
            //Debug("Load Points...");
           Dout("__loadCoordinates lpos:"+(string)l_pos+", lDest:"+(string)l_dest);
            // time =  distance/velocity
            
             time = (float)llVecDist(l_pos,(l_pos+l_dest))/TARGET_AFFINITY; 
             if(time < 0.2) time = .3;
             lCoordinate = [];
             lCoordinate +=l_dest; 
             lCoordinate += l_rot; // * any new rot relative to current position.
             lCoordinate +=time;
             pos =  l_pos+l_dest;
             vLastRelPos =pos;
             lastRot = llGetRot();
             //iStartTimer = TRUE;
             // target = __llTargetRemove((integer)target);  WHY REMOVE IT BEFORE YOU EVEN TRY TO GO TO IT ?
             Dout( "__loadCoordinates result At " + (string) llGetPos() + " KIFM to " + llDumpList2String(lCoordinate, ",") );
             llSetKeyframedMotion(lCoordinate, [KFM_DATA, KFM_TRANSLATION|KFM_ROTATION, KFM_MODE, KFM_FORWARD]);
            //iStartTimer = FALSE;
       
             return  llTarget(pos, 50.0);
}
_llWanderWithinKeyframe (vector home,  vector range, list c) {
    pos = llGetPos();
    iPos = llGetPos(); // THIS IS WHERE  WE are, do not change it!

    Dout("Wander within key frame from " + (string) iPos);
    list TYPE = [9] ; // ,16,32,64,128,126];
    integer vAreaParcelsqm = llList2Integer(llGetParcelDetails(iPos,[PARCEL_DETAILS_AREA]),0);
    vector area = < vAreaParcelsqm -.25, vAreaParcelsqm -.25,vAreaParcelsqm -.25>;
    vector bot = my_home-WANDER_RANGE/2.0;
    vector top = my_home+WANDER_RANGE/2.0;
    //llInstantMessage(llGetOwner(),"bot:"+(string)bot+"top:"+(string)top);
    //   if(TYPE_COUNT++ > 1) { TYPE_COUNT = 0; TYPE_FLIGHT =               
    //  (integer)(llFrand(7.0)); iPos = llGetPos();} 
   TYPE_FLIGHT = 0;
   if( TYPE_FLIGHT == 10) {TYPE_FLIGHT  == 0; iPos = llGetPos();}
    integer i = liN; // was 20, should be the number of frames the curve is divided into;
    //timer_wander = llGetUnixTime();
    do {
   
        nex_pos = clipRegion(bot,top,nextCoordinates(llList2Integer(TYPE,TYPE_FLIGHT) )); 
        //Dout("_llWanderWithinKeyframe:Process point:"+(string)nex_pos);
        Dout( "wanderwithin i = " + (string) i + " next_pos " + (string) nex_pos);
    }  while(checkInside2(bot,top,nex_pos) == FALSE && i-- >0); // this is the wrong place to decrement i
      
    if(nex_pos != ZERO_VECTOR && i!=0) {
         Dout("_llWanderWithinKeyframe: Moving from ipos: "+(string)iPos+" to next "+ (string)nex_pos); 
         if(TYPE_FLIGHT != 9)  newrot = llGetRot();
         target_wander_id = __loadCoordinates(iPos,(nex_pos-iPos),newrot, llFrand(FUDGE)+ (nex_pos.z)/SPEED,target_wander_id);
        
    }
    else Dout("Wander within no movewment because nex_pos = " + (string) nex_pos  + " and/or i = " + (string) i);
    // and now decrement I and repeat the loop
}

key owner;

default
{
    state_entry()
    {
        owner = llGetOwner();
         pos = llGetPos();
         iPos = pos;
         my_home = llGetPos();
         llSetLinkPrimitiveParamsFast(LINK_THIS,
    [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_CONVEX]);
        llSetKeyframedMotion([],[]);    // IMPORTANT, KILL ANY PRIM_PROERTY KFM
    }

    touch_start(integer total_number)
    {
        integer i = 3; // 10;
        do {
            _llWanderWithinKeyframe (llGetPos(),WANDER_RANGE, []);
        }  while(i-- > 0);
    }
   //at_target(integer tnum, vector targetpos, vector ourpos) {
   //    Dout("At target");
   //     if(tnum == target_wander_id) {   
   //     llSetKeyframedMotion([],[]);    // IMPORTANT otherwise it won't stop moving
   //          //iStartTimer = FALSE;
   //          target_wander_id = __llTargetRemove(target_wander_id);
   //      }
// }
    moving_end()
    {
        llOwnerSay("We have arrived");
        llSetKeyframedMotion([],[]);    // IMPORTANT otherwise it won't stop moving
        // AND NOW add code to go and calculate the nextr series of moves

    }
    
}

 

 

Link to comment
Share on other sites

Here is a stab at a pseudo-code (text flowchart) descrption of what I think you need to do

Set up initial conditions (range, parcel boundaries), kill any residual KFM

set b_i to 0

set bi_limit to frames

When touched, 

enter a move routine

if b_i == 0 call coeffirst,

increment b_i and if( b_i < bi_limit)  calculate a point on the bezier curve , clip it to parcel boundaries, initiate KFM

when moving_end occurs, go back into the increment b_i process to calculate the next point and move to it

 

 

Link to comment
Share on other sites

30 minutes ago, VirtualKitten said:

yes i will have to stop it but working out how to do the rebound on a n object in three d space is hard in 2d yes i can do it i think three not so easy

There's probably a more efficient way of getting the answer, but off the top of my head, if you have a vector v rebounding off of a surface with normal n at the point of collision, then something like:

rebound(vector v, vector n)
{
  v = -v;
  rotation r = llRotBetween(v,n);
  return v*r*r;
}

 

  • Like 1
Link to comment
Share on other sites

Thanks Quistess Alpha

So you mean 

vector rebound(vector v, vector n)
{
  v = -v;
  rotation r = llRotBetween(v,n);
  return v*r*r;
}

vector __collision (vector start)
{
        integer i =0;
        integer position =0;
        vector ikPOS = ZERO_VECTOR;
        list Ray = llCastRay(llGetPos()+<0.0,0.0,0.0>, llGetPos()+<0.0,0.0,0.0>,[RC_MAX_HITS,5]);
        vector mpos=llGetPos();
        do {
              key lkID = llList2Key(Ray,i);
              ikPOS = llList2Vector(Ray, i+1);
              position = i+1;
              i = llGetListLength(Ray )-1;
              i++;
         } while(i<1);
                                       
         if(position ==1 ) return rebound(start,ikPOS) ; else return ZERO_VECTOR;
 } 
// Main code call **************************************************
         vector newpos1 = ZERO_VECTOR;
         llOwnerSay("DEBUG : Get bezier");
         do {
             
              if (b_i == liN || b_i == 1) { b_i = 1;  coefisFirst();} 
              newrot = Vec2Rot(dBez( b_i/liN));
              newpos = (dBez( b_i/liN));
              b_i++;
              newpos1 =  __collision(newpos);
              if(newpos1 != ZERO_VECTOR) {
                 b_i = 1;  
                 newpos = newpos1;
                  // how to invert nxt bit  refFrame
                 coefisFirst();
               }  else {
                   newpos1= newpos;
               } 

        } while(newpos1 == ZERO_VECTOR);
        return newpos;

Will something like this work please ?

 

Hugs D

Edited by VirtualKitten
added
Link to comment
Share on other sites

22 minutes ago, VirtualKitten said:

Will something like this work please ?

I've not been following closely how all your code works, I just happened to glance on your question of how to figure out a reflection in 3d space, and found it interesting so I gave it a few minutes of thought, and gave a possible solution. How, if at all, that applies to your current project, isn't so interesting to me.

  • Like 1
  • Sad 1
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 842 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...