Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Tell if an object is coming at you

Zenick Aridian
Registered User
Join date: 1 Nov 2005
Posts: 8
11-25-2005 19:15
I'm trying to figure out how to tell if a object is moving directly towards my av position.
Christopher Omega
Oxymoron
Join date: 28 Mar 2003
Posts: 1,828
11-25-2005 21:57
The easiest way to do this is to get the angle between the vector pointing from the object at you to the vector representing that object's velocity. if the angle is smaller then a certain limit, then the object is coming towards you.

CODE

default {
state_entry() {
llSensorRepeat("", NULL_KEY, ACTIVE|PASSIVE, 96, TWO_PI, 5.0);
}
sensor(integer det) {
integer i;
for (i = 0; i < det; ++i) {
vector dVel = llDetectedVel(i);
vector offset = llGetPos() - llDetectedPos(i);
float angle = llRot2Angle(llRotBetween(llVecNorm(dVel), llVecNorm(offset)));
if (angle < PI && llVecMag(dVel) > 0) {
float dist = llVecMag(offset);
// Now we can use the tangent function
// to determine the distance between the object and us
// when it crosses our path.
float opp = llTan(angle) * dist;
list dBounds = llGetBoundingBox(llDetectedKey(i));
float boundsDist = llVecDist(llList2Vector(dBounds, 0), llList2Vector(dBounds, 1));
if (opp < boundsDist) {
// The object will hit us.
llOwnerSay(llDetectedName(i) + " is going to collide with me!");
}
}
}
}
}


Here's an illustration to help explain what im doing here:
CODE

Object
|\
|a\
| \
offset | \ velocity
| \
| \
| \
|__opp__\
Avatar

The "a" represents the angle we're computing. Once this angle is obtained, you can determine how far away the object will be from you (the avatar) when it crosses your path. If this distance (named opp, in the picture), is less then the distance between the object's corners, the object will bump into you. this wont be super-accurate by any means - it only determines if the object will collide with you using its bounding box - it wont take into account things like a large hole in the center of the object. It also doesnt account for rotation - if a wall-like box is heading towards you, it doesnt know if it heading towards you facing you with its large side or its thin side.

Hope this helps - lemme know if anything needs clarifying.
==Chris
_____________________
October 3rd is the Day Against DRM (Digital Restrictions Management), learn more at http://www.defectivebydesign.org/what_is_drm
Zenick Aridian
Registered User
Join date: 1 Nov 2005
Posts: 8
11-25-2005 22:42
thank you that's what i needed. that i would not have figured out.
Zenick Aridian
Registered User
Join date: 1 Nov 2005
Posts: 8
Bugs fixed
11-25-2005 23:02
default {
state_entry() {
llSensorRepeat("", NULL_KEY,"", 96, TWO_PI, 5.0);
}
sensor(integer det) {
integer i;
for (i = 0; i < det; ++i) {
vector dVel = llDetectedVel(i);
vector offset = llGetPos() - llDetectedPos(i);
float angle = llRot2Angle(llRotBetween(llVecNorm(dVel), llVecNorm(offset)));
if (angle < PI) {
float dist = llVecMag(offset);
// Now we can use the tangent function
// to determine the distance between the object and us
// when it crosses our path.
float opp = llTan(angle) * dist;
list dBounds = llGetBoundingBox(llDetectedKey(i));
float boundsDist = llVecDist(llList2Vector(dBounds, 0), llList2Vector(dBounds, 1));
if (opp < boundsDist) {
// The object will hit us.
llOwnerSay(llDetectedName(i) + " is going to collide with me!";);
}
}
}
}
}
Rickard Roentgen
Renaissance Punk
Join date: 4 Apr 2004
Posts: 1,869
11-29-2005 13:26
CODE

// Please Note: at_me_angle is assumed to be in radians, not degrees.
integer object_coming_at_me(vector object_velocity, vector object_position, float at_me_angle)
{
float deflection = llRot2Angle(llRotBetween(llVecNorm(llGetPos() - object_position), llVecNorm(object_velocity)));

if (deflection <= at_me_angle) {
return TRUE;
} else {
return FALSE;
}
}
_____________________
Luc Aubret
Oreo-eater
Join date: 14 Sep 2005
Posts: 86
11-30-2005 00:04
Is there any way to use this to determine what position an object on collision course is going to be at when it is, say, 1m away from you?
Seifert Surface
Mathematician
Join date: 14 Jun 2005
Posts: 912
11-30-2005 00:28
I think it should be possible to do all of these kinds of tests using dot products rather than converting to rotations and angles. I tend to avoid using angles whenever possible - the trig functions are slow in comparison to things like the dot product (which is just multiplication and addition).
_____________________
-Seifert Surface
2G!tGLf 2nLt9cG
Rickard Roentgen
Renaissance Punk
Join date: 4 Apr 2004
Posts: 1,869
11-30-2005 00:49
CODE

vector position_at_distance(vector object_velocity, vector object_position, float required_distance)
{
vector relative_position = llGetPos() - object_position;
vector velocity_direction = llVecNorm(object_velocity);
float distance_to_object = llVecMag(relative_position);
float deflection = llRot2Angle(llRotBetween(llVecNorm(relative_position), velocity_direction));
float closest_distance = llSin(deflection) * distance_to_object;

if (closest_distance > required_distance) {
// Object isn't going to pass within the required_distance.
return ZERO_VECTOR;
} else {
// Object does pass within the required_distance.
return (((llCos(deflection) * distance_to_object) - llSqrt(llPow(required_distance, 4.0) - llPow(closest_distance, 2.0))) * velocity_direction) + object_position;
}
}

This is untested, but I believe it will work.

He's right, this is the trig method and so slower, I'll see if I can work it out using cross and dot.
_____________________
Luc Aubret
Oreo-eater
Join date: 14 Sep 2005
Posts: 86
11-30-2005 01:05
From: Rickard Roentgen
CODE

vector position_at_distance(vector object_velocity, vector object_position, float required_distance)
{
vector relative_position = llGetPos() - object_position;
vector velocity_direction = llVecNorm(object_velocity);
float distance_to_object = llVecMag(relative_position);
float deflection = llRot2Angle(llRotBetween(llVecNorm(relative_position), velocity_direction));
float closest_distance = llSin(deflection) * distance_to_object;

if (closest_distance > required_distance) {
// Object isn't going to pass within the required_distance.
return ZERO_VECTOR;
} else {
// Object does pass within the required_distance.
return (((llCos(deflection) * distance_to_object) - llSqrt(llPow(required_distance, 4.0) - llPow(closest_distance, 2.0))) * velocity_direction) + object_position;
}
}

This is untested, but I believe it will work.

He's right, this is the trig method and so slower, I'll see if I can work it out using cross and dot.


Math! So that's how the hammerhead runs so nicely.
Willow McGettigan
Registered User
Join date: 30 Nov 2005
Posts: 7
11-30-2005 01:20
I'd like to see how this works, too - how you can figure out if something's coming at you, and rez an object to block it. I know, I know... there are shields that do this, but I want to know how, damnit, LOL!
Rickard Roentgen
Renaissance Punk
Join date: 4 Apr 2004
Posts: 1,869
11-30-2005 01:23
CODE

vector position_at_distance(vector object_velocity, vector object_position, float required_distance)
{
vector relative_position = llGetPos() - object_position;
vector velocity_direction = llVecNorm(object_velocity);
float distance_to_object = llVecMag(relative_position);
float deflection = llRot2Angle(llRotBetween(llVecNorm(relative_position), velocity_direction));
float closest_distance = llSin(deflection) * distance_to_object;

if (closest_distance > required_distance) {
// Object isn't going to pass within the required_distance.
return ZERO_VECTOR;
} else {
// Object does pass within the required_distance.
return (((llCos(deflection) * distance_to_object) - llSqrt(llFabs(llPow(required_distance, 4.0) - llPow(closest_distance, 2.0)))) * velocity_direction) + object_position;
}
}

Small correction, there has to be an llFabs() in that last return to keep from trying to sqrt() a negative number.

those shields typically use arrays of sensors, and a function something like this. to make this a shield, you would use a lot of sensors all detecting active objects repeating a lot, in each sensor event you would call this function passing it llDetectedVel(0) and llDetectedPos(0) and the distance your shield prims should rez at and if it returns anything but ZERO_VECTOR, rez a shield prim at the vector it returns.
_____________________
Rickard Roentgen
Renaissance Punk
Join date: 4 Apr 2004
Posts: 1,869
11-30-2005 01:31
heh, and math is not my strong point, but i've taken enough of it with a little trial and error i can usually figure out how to do something. Good chance my first two tries won't work quite as planned though.

If there are any math profs, majors, or people who make their living calculating motion in 3 space I'd be interested to see where my function could be simplified, sped up or approached differently.
_____________________
Luc Aubret
Oreo-eater
Join date: 14 Sep 2005
Posts: 86
11-30-2005 07:40
Still, an impressive bit of scripting. I'm unconvinced that rezzing prims is the best way to shield one's self - especially since in my experience a well-used llVolumeDetect works just as so-so - but I like the implications.
Rickard Roentgen
Renaissance Punk
Join date: 4 Apr 2004
Posts: 1,869
11-30-2005 08:32
the volume detect shielding is dead as of 1.7.
_____________________
Luc Aubret
Oreo-eater
Join date: 14 Sep 2005
Posts: 86
11-30-2005 10:01
Really?

My volume detect shield still seems to work. Not, y'know, great, but not any worse than it did in 1.6. I have mine follow me around at my position and become solid on collision with anything that's not an agent, and that seems to work okay. It won't really do much against fired bullets, but it's usually responsive enough to block anything using llMoveTo...

While I've got the floor, I just wanted to point out that that damn Hammerhead you make, Rickard, is about the smoothest-moving vehicle I've ever had the pleasure to pilot in SL. I don't mean to gush, but I just got out of one before coming to the forums, LOL.
Willow McGettigan
Registered User
Join date: 30 Nov 2005
Posts: 7
12-01-2005 00:25
I'm slightly confused by what you said about shield sensors, Rickard. Are you suggesting that shield scripts use several redundant sensors in the same script? Would these sensors be the same (by this I mean using the same rate, range, and type)? I'd never thought to do that.

Also, what would you suggest using as required_distance in your "is it coming to get me" math, Rickard? I tried using 1 or 2, but the script seemed to not pick up on anything - even my scripted boxes that hit me full-face - at all.
Zenick Aridian
Registered User
Join date: 1 Nov 2005
Posts: 8
12-01-2005 07:04
wow haven't check the fourms for a couple days.Thanks for the alternative script Rickard
i haven't tryed it yet but it looks a little more accurate in detection.As for use this as a shield i think it would be pointless just have a sensor to detect if the object is so close and rez prim there.The extra calculating would just slow down the rezzing making the shield less effective.
Rickard Roentgen
Renaissance Punk
Join date: 4 Apr 2004
Posts: 1,869
12-01-2005 12:04
From: Willow McGettigan
I'm slightly confused by what you said about shield sensors, Rickard. Are you suggesting that shield scripts use several redundant sensors in the same script? Would these sensors be the same (by this I mean using the same rate, range, and type)? I'd never thought to do that.

Also, what would you suggest using as required_distance in your "is it coming to get me" math, Rickard? I tried using 1 or 2, but the script seemed to not pick up on anything - even my scripted boxes that hit me full-face - at all.


multiple sensors, not in the same script. I've never built a shield so I'm repeating what I've been told and my own theories, but to get more persistant sensor coverage multiple scripts with one sensor per script, or multiple objects with one sensor script per object. The second one, multiple objects all pointed in different directions with limited detection cones would probably work better. Yes the function that gives position at required_distance might be a bit too slow. if you just want a script that rezzes an object between you and the incoming object at a certain distance, try this.

CODE

integer rez_shield(vector detected_position, vector detected_velocity, float danger_speed, float danger_distance)
{
if (llVecMag(detected_velocity) > danger_speed) {
vector relative_position = llGetRootPosition() - detected_position;
float distance = llVecMag(relative_position);
if (distance > danger_distance) {
if ((llFabs((llVecNorm(detected_velocity) * llVecNorm(relative_position)) - 1.0) * distance) < danger_distance) {
relative_position = llVecNorm(-relative_position);
llRezObject(llGetInventoryName(INVENTORY_OBJECT, 0), relative_position * danger_distance, ZERO_VECTOR, llRotBetween(<1.0, 0.0, 0.0>, relative_position), 1);
return TRUE;
}
}
}
return FALSE;
}


danger_speed should be about 10.0 meters per second I think, and danger_distance should be 2.0 to 3.0.

here's an example sensor event

CODE

sensor(integer n)
{
integer i;
boolean rezzed = FALSE;
for (i = 0; i < n && !rezzed; i += 1) {
rezzed = rez_shield(llDetectedPos(i), llDetectedVel(i), 10.0, 2.5);
}
}


maybe 6 or so objects all radiating sensors in different directions with PI*0.5 arcs could work. would need experimentation. In theory the more sensors the higher your reaction time. the more those sensors overlap the more shield prims may be rezzed for each incoming object. Please note that the more massive a shield prim, the slower it will rez. you want your shield prim to be just tall enough and wide enough to hide behind and as thin as possible.

Here's an alternate function that may rez more uneccessary shielding but will react faster.
CODE

integer fast_rez_shield(vector detected_position, vector detected_velocity, float danger_speed)
{
if (llVecMag(detected_velocity) > danger_speed) {
vector relative_direction = llVecNorm(detected_position - llGetRootPosition());
if ((llVecNorm(detected_velocity) * relative_direction) < -0.71) {
llRezObject("shield prim", relative_direction * 2.5, ZERO_VECTOR, llRotBetween(<1.0, 0.0, 0.0>, relative_direction), 1);
return TRUE;
}
}
}
return FALSE;
}
_____________________
Willow McGettigan
Registered User
Join date: 30 Nov 2005
Posts: 7
12-01-2005 13:25
Er... Rickard? I don't think your math is quite right on either of those (rez_shield and fast_rez_shield). I tried it out with plywood prims, and nothing would rez. When I added some debugging llOwnerSays, it told me that it was, in fact, trying to rez something but that that something was rezzing more than 138m from the object's position.

I wish I knew enough 3D math to fix it... :(
Rickard Roentgen
Renaissance Punk
Join date: 4 Apr 2004
Posts: 1,869
12-01-2005 15:21
From: Willow McGettigan
Er... Rickard? I don't think your math is quite right on either of those (rez_shield and fast_rez_shield). I tried it out with plywood prims, and nothing would rez. When I added some debugging llOwnerSays, it told me that it was, in fact, trying to rez something but that that something was rezzing more than 138m from the object's position.


oops, heh, it's a mistake I consistantly make :P. I end up with local coordinates not simulator relative. just add llGetPos() to the rez function. Here it the code is again with the fix.

CODE

integer rez_shield(vector detected_position, vector detected_velocity, float danger_speed, float danger_distance)
{
if (llVecMag(detected_velocity) > danger_speed) {
vector relative_position = llGetRootPosition() - detected_position;
float distance = llVecMag(relative_position);
if (distance > danger_distance) {
if ((llFabs((llVecNorm(detected_velocity) * llVecNorm(relative_position)) - 1.0) * distance) < danger_distance) {
relative_position = llVecNorm(-relative_position);
llRezObject(llGetInventoryName(INVENTORY_OBJECT, 0), (relative_position * danger_distance) + llGetPos(), ZERO_VECTOR, llRotBetween(<1.0, 0.0, 0.0>, relative_position), 1);
return TRUE;
}
}
}
return FALSE;
}


CODE

integer fast_rez_shield(vector detected_position, vector detected_velocity, float danger_speed)
{
if (llVecMag(detected_velocity) > danger_speed) {
vector relative_direction = llVecNorm(detected_position - llGetRootPosition());
if ((llVecNorm(detected_velocity) * relative_direction) < -0.71) {
llRezObject("shield prim", (relative_direction * 2.5) + llGetPos(), ZERO_VECTOR, llRotBetween(<1.0, 0.0, 0.0>, relative_direction), 1);
return TRUE;
}
}
}
return FALSE;
}


the -0.71 in the above function represents the return from a dot product. It's not precisely an angle but rather the cosine of an angle. for speed sake I didn't llAcos it. -0.71 is about 45 degrees. -1.0 would be heading right at you. 0.0 would be 90 degrees or on a tangent. 1.0 would be heading directly away from you.

So, to tighten up the approach angle, decrease -0.71 to something close to -1.0.
_____________________
Rickard Roentgen
Renaissance Punk
Join date: 4 Apr 2004
Posts: 1,869
12-01-2005 15:33
also, here's my original simple function that returns how accurately something is moving at you, rewritten to get rid of Rot2Angle and RotBetween (uses the dot product now). the return value is different too. Now instead of returning TRUE or FALSE it returns an angle you can check yourself.

CODE

// Please Note: the return value is in radians.
float angle_at_me(vector object_velocity, vector object_position)
{
return llAcos(llVecNorm(llGetPos() - object_position) * llVecNorm(object_velocity));
}

Yay for one line functions :P.

How to use...
CODE

if (angle_at_me(llDetectedVel(i), llDetectedPos(i)) < 0.785) { // 0.785 is approximately 45 degrees.
llShout("OMG, IT'S COMING THIS WAY!!!");
}
_____________________
Luc Aubret
Oreo-eater
Join date: 14 Sep 2005
Posts: 86
12-01-2005 23:35
Keep in mind, Willow, that Rickard's script here seems to take as an assumption that you want the forward (x) face facing towards the violating object. If you want the up (z) face (for example, if you plan on using a portion of a hollowed-out sphere as your protector, you'll want to adjust <1.0,0.0,0.0> to <0.0,0.0,1.0>.

Oh, and you'll need to replace boolean with... I suppose integer in this case, for LSL purposes. I'm sure you knew that, but y'know...
Rickard Roentgen
Renaissance Punk
Join date: 4 Apr 2004
Posts: 1,869
12-01-2005 23:59
lol, damn, been away from sl too long. Ya, thanks Luc, no bools in lsl. Integers it is.
_____________________