User:Dale Innis/AutomaticWalking
LSL Portal | Functions | Events | Types | Operators | Constants | Flow Control | Script Library | Categorized Library | Tutorials |
Intro
So I have my AvatarFollower script, which lets you automatically follow someone without having to keep track of them and push arrow keys and stuff.
And one of the nice side-benefits of that is that while you're following someone, you don't have to hold down any arrow keys, so you can type in chatboxes and stuff (and for that matter like sort inventory) while you're walking along. Not to mention camming about so as to get good pictures of the two of you walking.
(Getting pictures of yourself walking is a hard thing to do in SL!)
So I thought it would also be good to have something similar where instead of following someone, you could just walk forward without having to hold down an arrow key, so you could also type and cam and take pictures and stuff while still walking.
Code
Here's the current draft, more or less:
<lsl> // Tap fwd to walk forward, again or tap back to stop. // Side-arrows still turn you while walking forward // by Dale Innis
float RANGE = 2.0; // Meters away that we put the target float TAU = 1.0; // Make smaller for more rushed walking
integer tid = 0; integer walking = FALSE;
stopWalking() {
walking = FALSE; llTargetRemove(tid); llStopMoveToTarget(); llOwnerSay("No longer autowalking.");
}
startWalking() {
walking = TRUE; keepWalking();
}
keepWalking() {
if (llGetAgentInfo(llGetOwner()) & AGENT_FLYING) { stopWalking(); return; } llTargetRemove(tid); llStopMoveToTarget(); vector offset = <2*RANGE,0,0>*llGetRootRotation(); vector targetPos = llGetPos() + offset; targetPos.z += llGround(offset) - llGround(ZERO_VECTOR); // helps only on ground llMoveToTarget(targetPos,TAU); tid = llTarget(targetPos,RANGE/2.0);
}
default {
state_entry() { if (llGetAttached()!=0) llRequestPermissions(llGetOwner(),PERMISSION_TAKE_CONTROLS); } attach(key id) { if (id==NULL_KEY) return; } run_time_permissions(integer perm) { llTakeControls(CONTROL_FWD|CONTROL_BACK|CONTROL_ROT_LEFT|CONTROL_ROT_RIGHT|CONTROL_UP,TRUE,TRUE); } control(key id,integer level,integer edge) { if (llGetAgentInfo(llGetOwner()) & AGENT_FLYING) { stopWalking(); return; } integer tap = edge & level; if (tap & CONTROL_FWD) { if (walking) { stopWalking(); } else { startWalking(); } } if (tap & CONTROL_BACK) { if (walking) stopWalking(); } if (level & CONTROL_ROT_LEFT) { if (walking) keepWalking(); } if (level & CONTROL_ROT_RIGHT) { if (walking) keepWalking(); } }
on_rez(integer x) { llResetScript(); // Why not? }
at_target(integer tnum,vector tpos,vector ourpos) { if (walking) keepWalking(); }
} </lsl>
Notes
It's basically just like the avatar follower, except that what you are "following" is a spot a few meters in front of you, and every time you get too close to it, it pops out another few meters ahead.
This actually works! It's a little wonky, in that you turn rather slowly while autowalking (i.e. when you press left or right arrow, the camera moves at once, but your AV turns rather slowly, so you have a biggish turning radius), and it doesn't get along at all well with jumping (it basically prevents jumping, more or less).
The main problem is that it can't tell where the floor is, unless you're walking on the actual SL ground. If you are, say, walking on the deck of an airship or the floor of a skybox 2000m in the sky, the script will still see the official SL ground far beneath you, and (with the current code) try to make you follow the vertical contour of that ground as you walk.
The other way to approach this would be to ignore the vertical entirely, and have you always move toward a position that's in front of you and at the same z-height. The problem there is that when facing down a steepish hill (and sometimes up a shallowish one, for reasons I don't understand), you end up in a sort of flying-falling pose for a bit. And when facing up a too-steep hill (or toward an obstacle) sometimes you just stop.
I'm not sure what if anything can be done about those oddnesses. I may try using llApplyImpulse or llSetForce instead of llMoveToTarget; that might make a difference. And I may see if any of the new Pathfinding stuff would be useful here (in those places where it's active). If I don't get too lazy. :)