Don't click here unless you want to be banned.

LSL Wiki : AutobahnRoad

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are ia360925.us.archive.org

How to build Autobahn public and private roads Version 0

You can build two types of Autobahn roads.

1) Simple roads where the road is mostly flat and you don't have complex overpasses. The target position is always above the prim a set distance making it easy to drop a update script into an existing road.

2) Roads where the road controls the rotation of the vehicle. This makes great roller coasters.
For an overview see Autobahn Public roads that can be auto navigated by scripts

The prim name holds a key of the next road prim for each lane so that the vehicle can use llKey2Name to get the next prim's data.
The prim name also holds the road target position and rotation so that the vehicle only has to use a scanner when it first starts.

Each lane is composed of prims named "PublicRoad" Followed by data and choices of next keys

Fields are separated by ";" symbols to make it easier for the script to parse the string using llParseStringKeepNulls
  1. Standard version. = 0
  2. This Lane number = 1 added to make road updates easier
  3. Maximum recommended speed in m/s (optional)
  4. Descriptive road name (optional)
  5. Lane target position <X,Y,Z>. This is 1m above the road surface so that the vehicle does not have to process the rotation if it is built with a 1m high center.
  6. Lane Rotation <x,y,z,s> or blank for a simple Autobahn Road section. ZERO_ROTATION is defined as upright and pointing east.
  7. key for next prim of lane 1
  8. key for next prim of lane 2(optional)
  9. key for next prim of lane 3(optional)
  10. more lanes...

You can force vehicle to change lanes by leaving the key for that lane blank.
The vehicle should move to the nearest valid lane.

Making a simple Autobahn Road section

A simple section sets the "lane rotation" setting to blank and allows the vehicle to decide what direction to drive in the lanes. This allows for existing roads to updated to use the autobahn system by dropping a script into them.

The disadvantage is that by not defining what side of the road to drive on, you can have head on collisions.

Example:
Name "PublicRoad;0;1;20;Simple Road;" + (string)(llGetPos() + <0.,0.,1.5>) + ";" + (string)NextKey;
where the key's are the keys of the surrounding prims.


Making an Autobahn Road section

Getting the prim rotation correct is important since the vehicle uses this to orientate itself on to the road.

There is a test road in Charissa (10, 10, 95)

The forward direction is defined by the script.
<0,0,0,1> points east with Z up (ZERO_ROTATION)
<0,0,-1,0> points west with Z up
<0,0, 0.707, 0.707 points north with Z up
<0,0, -0.707, 0.707 points south with Z up

Since the name actually controls the road direction, you can make the prim any direction and modify the road update script

  1. Start by making a prim, then set the X axis to 10m. This will be the length of the section.
  2. Set the Y axis to thickness to 1m. This will be the resulting road thickness.
  3. Set the Z axis to 6m. This will be the lane width minus some shoulder.
  4. Now rotate it so that what was up is now pointing north. The Rotation should now be X=? Y=90 Z=270
  5. Set the texture to blank, color to grey and the repeats per side to 1 on all sides to improve frame rate.
  6. Select the texture on just the top and south side and set it to the library road texture.
  7. Library->?
  8. Select the top texture and set the texture to the following.
  9. U repeat = 1
    V repeat = 0.95
    Rotation to 0 degrees.
    U offset = 0
    V offset = .025
  10. Select the side texture and set the texture to the following.
  11. X repeat = 1
    Y repeat = 0.1
    Rotation to 0 degrees.
    X offset = 0
    Y offset = 0
  12. Rotate it to point east and get the prim rotation to update the script.

Scripts


This script works as long as the forward direction is correct for the scanner to see the next road segment.

It allows you to remove them using the "/65 remove" command and then allows you to update them again by dropping the script into one prim and giving it the "/65 update" command.
//public Road configuration script
//
//Released into the public domain by grumble Loudon and LaserFur Leonov
//
//V0.4 (not done, but works)
//
//defaults are used if not in notecard
integer m_Channel = 65;

integer m_lane = 1;
string  m_RoadName = "TestRoad";

integer m_PinNumber = 123;

//Rotate the road prim east (Z up) and touch to get "Actual Prim rotation" to set here
//rotation m_RotationAdjustment = < -0.7, 0, -0.7, 0>;
//rotation m_RotationAdjustment = <0.0, 0.0, 0.0, 1.0>;
 rotation m_RotationAdjustment = <-0.70711, -0.00000, 0.00000, 0.70711>;

vector m_LaneAdjustment = <0.0,0.0,1.5>;// set to 1m above prim surface.

//****************************************************************************************
integer m_DetectedScan = -1;
integer m_UpdateScript = 0;

integer m_MessageTimer = 0;
integer m_reSendMessage = 0;
string  m_reSendMessageStr = "";

//current data
key m_lane1Key;

vector m_LanePos;
rotation m_LaneRot;

vector m_testPos;
//****************************************************************************************
UpdateFloatText()
{    
    string Text;
    Text ="";
    Text += "Lane " + (string)m_lane + "\n";
    
    if (m_DetectedScan >= 0){
        Text += "Road is sensing " +  (string)m_DetectedScan + " Road Prims";
    };
    Text += "\n Actual Prim rotation = " + (string)llGetRot();
    Text += "\n Lane pos = " + (string)m_LanePos;
    Text += "\n Lane Rot = " + (string)m_LaneRot;
    Text += "\n Adj pos = " + (string)m_testPos;
    llSetText(Text ,<1,1,1>,1);
}
//*******************************************************************************
UpdateDescr(){
    
    //object name =  PublicRoad;0;Lane;speed;name;<pos 1m Up>;<Rotation>;key1;key2 ect...
    
    vector myPos =  llGetPos();
    rotation myRot =  llGetRot();
    rotation tRot1 =  ZERO_ROTATION /myRot;// 
    rotation tRot2 =  m_RotationAdjustment; //
    m_LaneRot = tRot1 * tRot2   ; // adjust for custom direction from prims view

    vector LaneAdj =  m_LaneAdjustment * m_LaneRot ;  //adjust the lane surface
    m_testPos = LaneAdj;
    
    m_LanePos =  myPos + LaneAdj; //1m above road surface
    
    string name;
    name = "PublicRoad;0;";         //prim name and version    
    name += (string)m_lane + ";";   // Lane number
    name += "20;";                  //recomended Speed limit in m/sec
    name += m_RoadName + ";";       //road name
    name += (string)m_LanePos + ";";  // X,y,z Lane position
    name += (string)m_LaneRot + ";";  // rotation. 
    //<0,0,0,1> points east,     
    //<0,0,-1,0> points west
    //<0,0, 0.707, 0.707 points north
    //<0,0, -0.707, 0.707 points south
    name += (string)m_lane1Key;     //Key to next prim
        
     
    llSetObjectName(name);
    UpdateFloatText();

}// update         
//********************************************************************************
integer ProcessCommand(string message,integer FromNotecard) // from either chat or notecard
{// processes message
//returns true if message should be re sent on chat
    integer resend = -1;
    
        if (message == "Scan"){
           llSensorRepeat("",NULL_KEY,PASSIVE|ACTIVE,18,0.5,3.1);
           resend = 0;

        }else if (message == "stop"){
            llSensorRemove(); 
            m_DetectedScan = -1;
            if (!FromNotecard){
                llSleep(.2);
                llWhisper(m_Channel,message);
            };
             
        }else if (message == "remove"){
            if (!FromNotecard){
                llSetText("" ,<1,1,1>,1);
                llSleep(.2);
                llWhisper(m_Channel,message);
                llRemoveInventory(llGetScriptName());
            };
           resend = 0;
        }else if (message == "update"){
            if (!FromNotecard){
                m_UpdateScript = TRUE;      //rez start pram tells next script
            };
        }else{
            UpdateDescr();
        };//               
                 
    return resend ;
    
}//ProcessCommand

//********************************************************************************
default
{
    state_entry()
    {
        
        //used to get m_RotationAdjustment
        //llOwnerSay( (string) (ZERO_ROTATION / llGetRot()));
               
        llSetRemoteScriptAccessPin(m_PinNumber);  
        llListen(m_Channel,"",NULL_KEY,"");
        
        UpdateDescr();
       
        m_lane1Key = NULL_KEY;
       
        if (llGetStartParameter() == 1)  m_UpdateScript = TRUE; //replicate
       
        llSensorRepeat("",NULL_KEY,PASSIVE|ACTIVE,18,0.5,2.4);            
 
        llSetTimerEvent(1.2);
    } //Entry
    //*****************************************************************************    
    on_rez(integer Reznumber){
        if (Reznumber  == 1){
            //  replicate
            m_UpdateScript = TRUE;
        }else{
            llResetScript();
        };  
    }  
    
    //*****************************************************************************    
    timer(){
        
        if (m_MessageTimer != 0)  --m_MessageTimer;
        

    } //timer
    //*****************************************************************************    
    touch(integer num){
    llOwnerSay((string)llGetRot());
    }
//*****************************************************************************    
    listen(integer channel, string name, key id, string message){
        
      if (m_MessageTimer == 0)  //we only respond to one command every 3 seconds
      {
            m_MessageTimer = 2;
            if ( m_reSendMessageStr != message ) //repeating message?
            {   
                m_reSendMessageStr = message;
                m_reSendMessage = ProcessCommand(message,FALSE);  
            }; //same
        }; //timer
        
    }// listen
//*****************************************************************************
 sensor(integer Num_Detected)
    {            
        m_DetectedScan  = 0; 
        
        integer useNum = -1;
        vector myPos = llGetPos();
        float closest = 100; 

        integer i;
        for (i = 0 ; i < Num_Detected; ++i){
            string name = llDetectedName(i);
            key dKey = llDetectedKey(i);
                        
            if (llGetSubString(name,0,10) == "PublicRoad;"){
                if ( llDetectedOwner(i) == llGetOwner()){
                
                    //does it need upating
                    if (m_UpdateScript){
                        if (llDetectedType(i) == PASSIVE){ //no script running
                            if ( llDetectedOwner(i) == llGetOwner()){
                                
                                llRemoteLoadScriptPin(dKey, llGetScriptName(), m_PinNumber, TRUE, 1);
                                jump ExitFor; //rescan
                            };//owner
                        };//passive
                    };  // update
    
                    
                    //is it my lane?
                    list Prams = llParseStringKeepNulls(name,[";"],[]);
                    integer listLenght = llGetListLength(Prams);
                    if (listLenght >= 7 ){
                        //0 PublicRoad
                        //1 version
                        integer DetLane = (integer)llList2String(Prams,2);//2 Lane
                        //3 speed
                        //m_DetectedRoadName = llList2String(Prams,4); //4 Name
                        
                        if  (DetLane == m_lane){
            
                            //is it ahead of me?
                            vector NextPos = llDetectedPos(i);
                            float dist = llVecDist(myPos , NextPos);

                            // check angle
                            // To do
            
                            if (dist < closest ){                
                                useNum = i;
                                closest  = dist;
                            };
                            ++m_DetectedScan;
                        };//lane
                    };//list
                        
                }; // owner
            };//name
        }; //sensor for 

        
        if (useNum != -1){
            key nearestKey = llDetectedKey(useNum);
            if (m_lane1Key != nearestKey){
                m_lane1Key = nearestKey;
                UpdateDescr();
            };

            m_UpdateScript = FALSE;
        };
@ExitFor;        
        UpdateDescr(); //test
        UpdateFloatText(); 
    }//sensor 
    
     no_sensor()
    {       
        m_DetectedScan = 0;   
        UpdateDescr();    //test
        UpdateFloatText();   
    
    }//no sensor
    //***************************************************************************** 
} //default
//*****************************************************************************

Notes

The vector and keys are at the end since the update script can replace them when the the editor truncates them.
As of 1.13 the editor truncates the name field to fit in the edit box when the prim it edited.

Note: pipe symbols and other symbols don't work in the description field since it's like a filename (V1.12)
As of 1.12 you can't read the description of other objects!
There is no comment on this page. [Display comments/form]