Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Wall climbing script (for any wall in SL)

Senuka Harbinger
A-Life, one bit at a time
Join date: 24 Oct 2005
Posts: 491
03-15-2009 03:31
I've hit my wit's end with trying to create a decent and fairly reliable wall climbing script so what follows is my thought process on how it should work and the (sometimes working sometimes not working) script I created thus far. hopefully someone out there with a better understanding of SL physics and the collision events will be able to help me out.

current issues:

**climbing speed is very fast (about 10m/s) no matter how strong an impulse/push I use.
**sometimes the avatar will just stop climbing for no apparent reason (even though it's still colliding) and begin to "Fall" while floating.


thought process:

*You avatar is walking along and it runs into something (oh noes).
*The "something" turns out to be in front of you, and you are lower than it's lower edge so lets climb up by pushing (applying an impulse) upwards.
*You're still colliding with something, but it's the "something" you decided to climb, so continue to push upwards (and forwards to continue the collision).
*you stopped colliding with what you wanted to climb so stop pushing upwards

so based off these "simple" assumptions I created, re-created, debugged, trouble shot, commented, and am about to take out back and shoot.... the following script

CODE

integer walking;
vector wallpos;
string direction;
integer infront(vector mypos, vector tarpos)
{
vector mydir=llRot2Fwd(llGetRot());
vector tardir=llVecNorm(tarpos-mypos);
if(llVecMag(mydir + tardir) <1)
{
return FALSE;
}
else
{
return TRUE;
}
}

key wall;


default
{
collision_start(integer num)
{
//llOwnerSay("collided");
vector mypos=llGetPos();
vector tarpos=llDetectedPos(0);
vector wallheight=llList2Vector(llGetBoundingBox(llDetectedKey(0)),0)+tarpos;
if(infront(mypos,tarpos)==TRUE)//we hit something that's infront of us
{
if(mypos.z >= wallheight.z)//We're above the bottom of the wall

{
wall=llDetectedKey(0);
wallpos=tarpos;
llSetBuoyancy(1);//impulse doesn't work that well if we're not "floaty"
llApplyImpulse(llRot2Fwd(llGetRot()),TRUE);
//llSetText("climbing wall: " + (string)wall,<1,1,1>,1);
llSetTimerEvent(.5);//debug display
}
}
}

collision(integer num)
{
if(llDetectedKey(0)==wall)//we're still colliding with the wall we're supposed to be climbing
{
llApplyImpulse(llRot2Fwd(llGetCameraRot())+<0,0,.125>*llGetMass(),TRUE);
//llPushObject(llGetOwner(), <0,0,1>*llGetMass()+llGetVel(), ZERO_VECTOR, TRUE);
}
else//we're not hitting the wall we're supposed to be climbing
{
llSetBuoyancy(0);
//llSetText("",<1,1,1>,0);
}
}

collision_end(integer num)
{
vector mypos=llGetPos();
vector tarpos=llDetectedPos(0);
vector wallheight=llList2Vector(llGetBoundingBox(llDetectedKey(0)),1)+tarpos;
if(wall==llDetectedKey(0))//we stopped colliding with the wall we're supposed to be climbing
{
if(wallheight.z/2+tarpos.z < mypos.z)//we're above the wall we're supposed to be climbing
{
//llApplyImpulse(llRot2Fwd(llGetRot())*2+<0,0,1>*llGetMass(),TRUE);
//llSetText("",<1,1,1>,0);
llSetBuoyancy(0);
}
else//we're still below the wall we're supposed to be climbing
{
llApplyImpulse(llRot2Fwd(llGetCameraRot())+<0,0,1>,TRUE);
}
}
}

timer()//debug display
{
vector walltop=llList2Vector(llGetBoundingBox(wall),1)+wallpos;
vector wallbottom=llList2Vector(llGetBoundingBox(wall),0)+wallpos;
llSetText("Wall Key: " +(string)wall + "\n My Position: " + (string)llGetPos() + "\n Wall's lower edge height: " + (string)wallbottom.z + "\n wall's upper edge height: "+ (string)walltop.z,<1,1,1>,1);
}

}
_____________________
My SLExchange shop

Typos are forgiven; desecrating the english language with reckless abandon and necrophilic acts is not.


The function is working perfectly fine. It's just not working the way you wanted it to work.
DoteDote Edison
Thinks Too Much
Join date: 6 Jun 2004
Posts: 790
03-16-2009 17:26
Since the switch to mono, I've found llMinEventDelay(0.2) to be fairly helpful when dealing with collision() or control() scripts where the events trigger too fast. Too bad we can specify the events to be delayed, such as llMinEventDelay(0.2, [EVENT_COLLISION, EVENT_CONTROL]).

http://lslwiki.net/lslwiki/wakka.php?wakka=llMinEventDelay
Tanith Rosenbaum
Registered User
Join date: 10 Sep 2008
Posts: 42
03-18-2009 14:12
From: Senuka Harbinger


**climbing speed is very fast (about 10m/s) no matter how strong an impulse/push I use.

looks a bit klutzy, but this works in my scripts (Have to look up the actual code, this is from memory). Put this inside your collision event:

float desired_speed = 1.0;
if(llVecMag(llGetVel()) < desired_speed)
{
llApplyImpulse(llRot2Fwd(llGetCameraRot())+<0,0,.125>*llGetMass(),TRUE);
}

**sometimes the avatar will just stop climbing for no apparent reason (even though it's still colliding) and begin to "Fall" while floating.

The avatars have used up their "Energy". Physical objects and avis have an amount of "Energy", which is depleted with certain physical operations, and gets replenished over time. Also, with sinking energy, the effect of llApplyImpulse will become smaller. If you run into this you might need to lower the rate of pushes, so that the energy will be depleted at a rate lower or equal to the rate it gets replenished with to give you a consistent effect.

See: http://www.lslwiki.net/lslwiki/wakka.php?wakka=Energy and http://wiki.secondlife.com/wiki/Energy

Energy depletion per application of llApplyImpulse is in your case:
float deplet = llVecMag(llRot2Fwd(llGetCameraRot())+<0,0,.125>*llGetMass()) / 20000.0;


Replenishment per second is:
float replen = 200.0/llGetMass();

float energy_balance = replen/(deplet*20); will give you a value describing the ratio between depletion and replenishment. The 20 is 1/0.05, the number of collision events you can have per second at the defaut event delay of 0.05 seconds) All above 1 is good, if it is below 1 you need to calculate the minimum time intervals you can apply the impulse without running out of energy. Actually you might want to just do that all the time and set llMinEventDelay accordingly. Use llMinEventDelay(replen/deplet); to calculate that value and set the minimum event delay accordingly.

I hope that helped.

Cheers
Tanith

P.S.: Maybe adding this to your debug function (the timer) might help diagnose if it indeed is an energy problem in the first place: llSetText((string)llGetEnergy(), <1.0,1.0,1.0>, 1.0);
Felix Stourmead
Registered User
Join date: 7 Dec 2008
Posts: 6
03-23-2009 22:12
also try testing it on a physical object, from what ive seen most of them dont work on non physicals