Double Tap Detection

From Second Life Wiki
Revision as of 04:47, 1 August 2008 by BETLOG Hax (talk | contribs)
Jump to navigation Jump to search

Double Tap Detection without Timers

This is an example to show one method of detecting a double tap of a movement key without using a timer. --Eyana Yohkoh 19:09, 27 August 2007 (PDT)

<lsl> // Dash/dodge template script by Eyana Yohkoh // // ///////

// This script is an example of a way to detect a double tap on movement // keys to trigger a function. // There are multiple ways to detect a double tap, and this method quite // possibly is not the best, but this certainly works.


// debugging stuff: // integer debug = FALSE; // set this to TRUE if you want to hear debugging messages

debugging(string debugMsg) // if debug is TRUE, then this is what will send messages { // I put this in a function for ease of adding more debug messages

   if ( debug )            
   {
       llOwnerSay(debugMsg);
   }

}


// getting the time for the comparison ///////// float strTime; // used to store the current time float time;

getSeconds() {

   string timestamp    = llGetTimestamp();                 
                                       // first part of getting the current time with milliseconds
                                       // this gives a strange time format so it was easier for me
                                       // to just grab the very end of the time to get the
                                       // fractional seconds.
   string subTime      = llGetSubString(timestamp, 19, 25);                                        
   float wallclock     = llGetWallclock();
                           // this gets the current time in seconds
                           // can't use this for a check without the above stuff because
                           // it does not do decimal places
                           
   strTime = (float)subTime + wallclock;
                           // appending milliseconds to the end of the rounded off seconds
                           // you could just do without this and test with seconds and milliseconds
                           // but that would cause problems with the comparison check for when
                           // double tapping at the cusp of a completed minute
                           
   debugging((string)strTime);             // debug message for testing purposes

}

// comparing the stored time with the current tap time ///////////

float storedTime; // number will be stored at the end of a tap for comparison float recentTime; // stored immediately on tapping for comparing with the stored

compareTimes(float stored, float recent) // find the difference between the times { // example use: compareTimes(storedTime, recentTime)

   time = recent - stored;
   debugging((string)recent + " - " + (string)stored + " = " +  (string)time);

}


resetStored() {

   storedTime = 0;

}

float interval = 0.5; // time between double taps

                       // default interval is 0.5 seems to be a good number
                       // 0.2 is too fast for some people, 1.0 is far too slow


doubleTap() {

   if ( time < interval )
   {
       llSay(0, "Double tap detected");
   }

}

key avatar; requestPerms() // permissions we want to take: {

   integer permissions = PERMISSION_TAKE_CONTROLS;
   llRequestPermissions(avatar, permissions);          // avatar is snagged when object is attached

}

takeControls() // what controls to take. pared down for the example. {

   integer controls    =   CONTROL_FWD;
                           
   llTakeControls(controls, TRUE, TRUE);

}

default {

   on_rez(integer reznum)
   {
       llReleaseControls();            // release controls just in case
       resetStored();                  // reset all stored numbers
       debugging("Debug messages are turned on.");
   }
   run_time_permissions(integer perms)
   {
       if ( perms > 0 )            // if permissions are granted then take controls
       {
           takeControls();
       }
   }
   
   attach(key id)
   {
       if ( id != NULL_KEY )       // if id is NULL then it's not attached to a person!
       {
           avatar = id;            // store the key for later use without need to reset
           requestPerms();         // get permissions
       }
       else                        // since it's no longer attached, then no need for control
       {
           llReleaseControls();
       }
   }
   control(key id, integer held, integer change) 
   {
       integer pressed = held & change;
                   
       if ( pressed & CONTROL_FWD )
       {
           getSeconds();
           recentTime = strTime;                   // store the recent time 
                                                   // that was just found with getSeconds()
           compareTimes(storedTime, recentTime);   // comparing times
           doubleTap();                            // this will trigger for double taps!
           storedTime = recentTime;                // store the recent time for later in case
                                                   // this time was not a successful double tap
                                                   // but was possibly the first key press for the
                                                   // double tap
       }
   }

} </lsl>


Double-tap detection - this example warps user at maximum velocity. [Functional code, paste to script, add to object, wear object, double tap forward key to test.]

<lsl> // // BETLOG Hax // AEST: 20080801 2227 [SLT: 20080801 0527] //---------------------------------- // SHARED CONFIGURATION //---------------------------------- // CONFIGURATION float gDoubleTap = 0.1; //---------------------------------- // CORE CODE integer gWarpActive = FALSE; //---------------------------------- default {

   state_entry()
   {
       if (llGetAttached())
           llRequestPermissions(llGetOwner(),PERMISSION_TAKE_CONTROLS);
   }
   attach(key id)
   {
       if (llGetAttached())
           llRequestPermissions(llGetOwner(),PERMISSION_TAKE_CONTROLS);
   }
   run_time_permissions(integer perms)
   {
       if(~perms & PERMISSION_TAKE_CONTROLS)
           llReleaseControls();
       else
       {
           llTakeControls(0
               | CONTROL_FWD
               | CONTROL_BACK
               | CONTROL_LEFT
               | CONTROL_RIGHT

// | CONTROL_ROT_LEFT // | CONTROL_ROT_RIGHT

               | CONTROL_UP
               | CONTROL_DOWN

// | CONTROL_LBUTTON // | CONTROL_ML_LBUTTON

           ,TRUE, TRUE);
           llOwnerSay("Ready - Doubletap frequency: "+(string)gDoubleTap);
       }
   }
   control(key id, integer pressed, integer change)
   {
       integer start = pressed & change;
       integer end = ~pressed & change;
       integer held = pressed & ~change;
       integer unheld = ~(pressed | change);
       //----------------------------------
       if (start & (CONTROL_FWD|CONTROL_BACK
                   |CONTROL_UP|CONTROL_DOWN
                   |CONTROL_LEFT//|CONTROL_ROT_LEFT
                   |CONTROL_RIGHT//|CONTROL_ROT_RIGHT
       ))
       {
           if (llGetTime() <= gDoubleTap)
           {
               if (-change == gWarpActive) //negative value is used to transfer meaning without another global.
                   gWarpActive = 1;
           }
       }
       //----------------------------------
       if (end & (CONTROL_FWD|CONTROL_BACK
                   |CONTROL_UP|CONTROL_DOWN
                   |CONTROL_LEFT//|CONTROL_ROT_LEFT
                   |CONTROL_RIGHT//|CONTROL_ROT_RIGHT
       ))
       {
           gWarpActive = -change;  //negative value is used to transfer meaning without another global.  
           llResetTime();
       }
       //----------------------------------
       if (held & CONTROL_FWD)
       {
           if (gWarpActive > 0)
           {
               llPushObject(
                   llGetOwner()
                   ,llRot2Fwd(llGetRot())*0x0FFFFFFF //forward
                   ,ZERO_VECTOR
                   ,FALSE
               );
           }
       }
       //----------------------------------
       // ADD THE REST OF THE KEYS/DIRECTIONS HERE

// ,-llRot2Fwd(llGetRot())*0x0FFFFFFF //back // ,llRot2Left(llGetRot())*0x0FFFFFFF //left // ,-llRot2Left(llGetRot())*0x0FFFFFFF //right // ,llRot2up(llGetRot())*0x0FFFFFFF //up // ,-llRot2Up(llGetRot())*0x0FFFFFFF //down

   }

} </lsl>