Jump to content

Camera Control for Vehicle with Multiple Riders


Erwin Solo
 Share

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

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

Recommended Posts

I have a vehicle for which I have eight seats.  

I want the first person who sits to be the Driver; this part is working fine.

If the Driver hops off the vehicle, I want the next person in line to become the Driver; this part is working fine.

I want all eight riders to have their cameras set to follow mode as shown in http://wiki.secondlife.com/wiki/LlSetCameraParams.

My strategy is that when any person sits (gets on) or stands (hops off) the vehicle, I then work backward from the end of the linkset requesting camera permissions for each rider, one by one, and setting up camera-following as shown in http://wiki.secondlife.com/wiki/LlSetCameraParams.  Then, when my down-counting loop gets to the first avatar on the linkset, I request both camera-following and llTakeControls for them.  

The result I'm getting is that the first avatar on the linkset is becoming the driver (llTakeControls() is working) and that the Avatar's camera is placed in follow mode.  However, the problem is that none of the other avatars have their cameras placed in follow mode; this is the problem I need help with.

 

My code

Camera Follow Function

fct_Camera_Follow()
{
    llClearCameraParams(); // reset camera to default
    llSetCameraParams([
        CAMERA_ACTIVE, 1, // 1 is active, 0 is inactive
        CAMERA_BEHINDNESS_ANGLE, 0.0, // (0 to 180) degrees
        CAMERA_BEHINDNESS_LAG, 0.0, // (0 to 3) seconds
        CAMERA_DISTANCE, 1.0, // ( 0.5 to 10) meters
      //CAMERA_FOCUS, <0,0,5>, // region relative position
        CAMERA_FOCUS_LAG, 0.05 , // (0 to 3) seconds
        CAMERA_FOCUS_LOCKED, FALSE, // (TRUE or FALSE)
        CAMERA_FOCUS_THRESHOLD, 0.0, // (0 to 4) meters
        CAMERA_PITCH, 10.0, // (-45 to 80) degrees
      //CAMERA_POSITION, <0,0,0>, // region relative position
        CAMERA_POSITION_LAG, 0.0, // (0 to 3) seconds
        CAMERA_POSITION_LOCKED, FALSE, // (TRUE or FALSE)
        CAMERA_POSITION_THRESHOLD, 0.0, // (0 to 4) meters
        CAMERA_FOCUS_OFFSET, <0.0, 0.0, 1.5> // <-10,-10,-10> to <10,10,10> meters
    ]);
}

 

Sit (get on vehicle) Stand (get off) Detector

changed(integer change)
    {
        if (change & CHANGED_LINK)
        {
            fct_Driver_Rider_Permissions();
        }
    }

 

Update: The problem was that the entire fct_Driver_Rider_Permissions() loop executes before the first  run_time_permissions(integer perm) is serviced.  The fix was to make the sitter-index a global variable and split the logic of the loop between the changed(integer change) event and the run_time_permissions(integer perm) event.  The changed(integer change)  event starts the loop, and the sitter-index will increments within the run_time_permissions(integer perm) event.  The run_time_permissions(integer perm)  event will call itself recursively as the sitter-index works its way down the link list.  Thus, permissions are handled for each avatar in sequence, with the driver being handled last.  If a new sitter arrives, or one sitter stands, the change (integer change) event will reset the index and the loop will execute once again, beginning with the last Avatar-link on the linkset, working its way back down the linkset and making the lowest-numbered link-Avatar the driver all over again.  The fix is posted in a follow-up message.

Permissions Requester

fct_Driver_Rider_Permissions()
{
    integer iNumberOfPrims = llGetNumberOfPrims(); // total number of prims in linkset
    integer iNonAvatar = llGetObjectPrimCount(llGetKey());  // number of prims in linkset not counting seated avatars

    if (iNonAvatar >= iNumberOfPrims) // no riders
    {
        llSetStatus( STATUS_PHYSICS, FALSE );  // turn physics off
    }
  
    else if (iNonAvatar < iNumberOfPrims) // one or more riders
    {
         integer iIndex = iNumberOfPrims ; 
        do
        {
            key kAvatar = llGetLinkKey(iIndex); 

            if (llGetAgentSize(kAvatar)) // if valid avatar on region
            {
                if ( iIndex == (iNonAvatar + 1) )  // avatar that I want to be the driver
                {
                    llRequestPermissions( kAvatar, (PERMISSION_TAKE_CONTROLS | PERMISSION_CONTROL_CAMERA) );
                }

                else if (llGetAgentSize(kAvatar)) // if valid key
                {
                    llRequestPermissions( kAvatar, (PERMISSION_CONTROL_CAMERA) );
                }
            }       
        }    
        while(--iIndex > iNonAvatar);
    }
}

 

Permissions Handler

    run_time_permissions(integer perm)
    {
       
        if (perm & (PERMISSION_TAKE_CONTROLS | PERMISSION_CONTROL_CAMERA) )
        {
            fct_Camera_Follow();
            gkDrivingAvatar = llGetPermissionsKey();
             llTakeControls(
                CONTROL_FWD |
                CONTROL_BACK |
                CONTROL_LEFT |
                CONTROL_RIGHT |
                CONTROL_ROT_LEFT |
                CONTROL_ROT_RIGHT |
                CONTROL_UP |
                CONTROL_DOWN |
                0, TRUE, FALSE);
                // | 0 is for edit convenience,
                // it does not change the mask.
             llSetStatus( STATUS_PHYSICS, TRUE );  
             llRegionSayTo(gkDrivingAvatar, 0, Who(gkDrivingAvatar) + ", you are now the Driver (private message).");
        }

       else if (perm & PERMISSION_CONTROL_CAMERA) fct_Camera_Follow(); // make camera follow
        
    }

 

Now, I realize that a script can only remember permissions for one avatar at a time, but I thought that once an Avatar's camera got put in follow mode that it would stay there.  Surely I don't need one script per avatar times 8 avatars to make the cameras follow.

I also think I'll have  permissions race with 8 avatars, because the permissions events won't necessarily be serviced in the same order they were called.  But I have a plan for that, once I get the basic functionality working with two avatars.

Edited by Erwin Solo
Edited to explain the problem after discovery and preview the solution.
Link to comment
Share on other sites

am pretty sure we do need a script for each avatar to maintain the camera permissions for each

having a each script helps with animations as well.  Say our vehicle is a bobsled.  Up to 8 avatars sitting in a row.  The driver will have a steering animation. The passengers in a hug animation.  When a person gets off (stands) the agents behind move forward.  The driver like you say is TakeControls

a thing with each own script is that we can change the animations for all the riders depending on what is happening.  Like the bobsled could crash and everybody falls out. Animate them out, then animate them back in.  Or when cross the finish line then everybody arms up.  etc etc   

Link to comment
Share on other sites

Thanks, @Mollymews.  I am using @Casper Warden's SimpleSit to control all the animations for all 8 with one script.  Since my Driver's camera is controlled okay, I think it is not an issue of my Camera Controller fighting with his.  His should do one camera setting at sit-time and then get out of the way.  I just have to make sure mine follows his, and the fact that mine is working for the Driver indicates that mine follows his okay.

Edited by Erwin Solo
Link to comment
Share on other sites

Well, what I'm working on now is to make the sitter-index a global variable, and split the logic of the loop between the changed(integer change) event and the run_time_permissions(integer perm) event.  The changed(integer change)  event will start the loop, and the sitter-index will increment within the run_time_permissions(integer perm) event.  The run_time_permissions(integer perm)  event will call itself recursively as the sitter-index works its way down the link list.  Thus, permissions will be handled for each avatar in sequence, with the driver being handled last.  If a new sitter arrives, or one sitter stands, the  changed(integer change) event will reset the index and the loop will execute once again, beginning with the last Avatar-link on the linkset, working its way backwards down the linkset and making the lowest-numbered link-Avatar the driver all over again.

  • Like 1
Link to comment
Share on other sites

Well. It seems to be working now

Applicable Global Variables

integer giNonAvatar;  // number of prims in linkset not counting seated avatars
integer giNumberOfPrims; // total number of prims in linkset
integer giObjCountInit; // Object Count at initialization (not counting seated avatars)
integer giSitterIndex; 

 

 

 

 

 

Recursion in Run Time Permissions Event

    run_time_permissions(integer perm)
    {
        if ( (perm & PERMISSION_TAKE_CONTROLS) && (perm & PERMISSION_CONTROL_CAMERA) )
        {
            fct_Camera_Follow();
            gkDrivingAvatar = llGetPermissionsKey();
             llTakeControls(
                CONTROL_FWD |
                CONTROL_BACK |
                CONTROL_LEFT |
                CONTROL_RIGHT |
                CONTROL_ROT_LEFT |
                CONTROL_ROT_RIGHT |
                CONTROL_UP |
                CONTROL_DOWN |
                0, TRUE, FALSE);
                // | 0 is for edit convenience,
                // it does not change the mask.
             llSetStatus( STATUS_PHYSICS, TRUE );  
             llRegionSayTo(gkDrivingAvatar, PUBLIC_CHANNEL, fct_Who(gkDrivingAvatar) + ", you are now the Driver (private message).");
        }

        else if (perm & PERMISSION_CONTROL_CAMERA) 
        { 
            fct_Camera_Follow(); // make camera follow
            
            giSitterIndex--; // decrement index to be used inside run_time_permissions(integer perm) event.  
            key kAvatar = llGetLinkKey(giSitterIndex); // key of Avatar among those seated
            
            if (llGetAgentSize(kAvatar)) // if valid avatar on region
            {
                if ( giSitterIndex == (giNonAvatar + 1) )  // driving avatar
                {
                    llRequestPermissions( kAvatar, (PERMISSION_TAKE_CONTROLS | PERMISSION_CONTROL_CAMERA) );
                }

                else 
                {
                    llRequestPermissions( kAvatar, (PERMISSION_CONTROL_CAMERA) );
                }
            }
        }
    }

 

 

Link to comment
Share on other sites

21 minutes ago, Mollymews said:

if haven't made anything like this myself.  I only have questions really trying to work out how it might be done

a camera question would be: What happens when a passenger presses Esc ?  Does it matter that the camera is no longer in the follow position ?

I haven't tested it rigorously, but it seems to behave like one would want it to behave.  Essentially, camera-follow-mode (http://wiki.secondlife.com/wiki/LlSetCameraParams) becomes the new "default" for the Avatar until the Avatar stands (hops off the vehicle).  So, if the Avatar goes into flycam-mode, then hitting ESC puts them back in camera-follow-mode mode.  The camera-behavior terminates when the Avatar stands (hops off the vehicle). 

  • Thanks 2
Link to comment
Share on other sites

On 11/10/2019 at 2:13 PM, Erwin Solo said:

Well, what I'm working on now is to make the sitter-index a global variable, and split the logic of the loop between the changed(integer change) event and the run_time_permissions(integer perm) event.  The changed(integer change)  event will start the loop, and the sitter-index will increment within the run_time_permissions(integer perm) event.  The run_time_permissions(integer perm)  event will call itself recursively as the sitter-index works its way down the link list.  Thus, permissions will be handled for each avatar in sequence, with the driver being handled last.  If a new sitter arrives, or one sitter stands, the  changed(integer change) event will reset the index and the loop will execute once again, beginning with the last Avatar-link on the linkset, working its way backwards down the linkset and making the lowest-numbered link-Avatar the driver all over again.

i really like this. Is an approach that I haven't thought about before. It opens up all kinds of things

like a two person sitter for example with animation changeouts.  Only need one script to do it all this way. Even setting up the animations (similar to AvPos) would be a lot less complicated and resource friendly I think

  • Like 1
Link to comment
Share on other sites

I get how this works, it just raises naive questions for me about how scripted cams work, and specifically how they work in vehicles.

I vaguely recall using a "follow cam" like this in a vehicle and needing to refresh the cam settings each time there was a sim crossing. Is that right, or was I doing something else wrong? (or just misremembering the whole thing?)

Also, I can't remember now why I even needed to use a follow cam (llSetCameraParams) instead of simple prim property cam settings (llSetCameraEyeOffset and -AtOffset). I know I'd need the active function if I wanted to switch cam settings again sometime after the avatar sits, but I've forgotten why else. Can anyone refresh my memory and save me testing in-world?

  • Like 1
Link to comment
Share on other sites

6 hours ago, Mollymews said:

like a two person sitter for example with animation changeouts.  Only need one script to do it all this way. Even setting up the animations (similar to AvPos) would be a lot less complicated and resource friendly I think

I think so too, and have done it that way for my own seating without evident ill effects, but I've been warned that avatars standing (or teleporting away) could get stuck in their last sit animation because the script can't llStopAnimation without re-requesting permission from the now absent agent. AFAIK, though, the viewer automatically stops all those animations as a side-effect of leaving the seat, and I've never myself observed that to fail. So if that's a real problem it would be good to know how it arises because otherwise, yeah, script scheduler resources are consumed by idle sit scripts duplicated for each potential sitter.

Edited by Qie Niangao
  • Like 2
Link to comment
Share on other sites

has been quite a long while since I made vehicles but I do remember scripted camera breaking on region crossings, (animations as well).  As I remember I ended up polling for agent on region change, and when found then resetting the camera and animation. Polling was/is to deal with the tiny window when vehicle (script) and agent can be on different regions until the crossing fully resolves for both

  • Like 1
Link to comment
Share on other sites

4 minutes ago, Qie Niangao said:

AFAIK, though, the viewer automatically stops all those animations as a side-effect of leaving the seat, and I've never myself observed that to fail

i  can't remember when Linden did it, but am pretty sure they changed the system so that animations stop when a agent is detached from an object, whether that be Stand, teleport or log out

i do remember tho how it used to be as you mention. Teleporting from a sit would not stop the animation

 

  • Like 2
Link to comment
Share on other sites

Okay, so to check for region change, one just adds that as follows.  Still there is a race at region crossing because there are nine things crossing the region: 1 vehicle and 8 avatars.

 

changed(integer change)
    {
        if (change & (CHANGED_LINK | CHANGED_REGION) )
        {
            fct_Driver_Rider_Permissions();
        }
    }

Link to comment
Share on other sites

Erwin, if you haven't already, you might want to think about testing for the presence of an agent on CHANGED_REGION, as there is a tiny window on region crossings when the agent can still be on the previous region when the vehicle script permissions code executes on region change

when a agent is not found, yet should be because the linked prim count is the same, then we need to skip them so to not swamp the script owner with permissions error messages. Polling for the latecomers for some amount of time until we give up on them

knowing that if an agent did get unseated by the crossing then we pick them back up with CHANGED_LINK  if they get back on

Edited by Mollymews
back on
Link to comment
Share on other sites

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