Virtual Line linking 2 objects
#1

I know this is not something really hard to script but ive been away from scripting for 5 monthes and I somehow lost my creativity.
Anyway Im asking if there is a way to create a virtual line (not an object) linking two real objects (for exmple two water bottles) and then ofc get its coords ect..
To make things more clear, I will need this to detect for exmple as to whether a player has walked between the 2 objects. (and I insist, it is a line, not a range or an area)
Reply
#2

Ok, so its not to easy but let me try

Create 2 variable in your pawno.. thay create an object..

Then make a stock like this

LinkObjectToObject(objectid,targetid)

And you can do that
Reply
#3

Quote:
Originally Posted by Battlezone
Посмотреть сообщение
I know this is not something really hard to script but ive been away from scripting for 5 monthes and I somehow lost my creativity.
Anyway Im asking if there is a way to create a virtual line (not an object) linking two real objects (for exmple two water bottles) and then ofc get its coords ect..
To make things more clear, I will need this to detect for exmple as to whether a player has walked between the 2 objects. (and I insist, it is a line, not a range or an area)
If the two bottles are aligned horizontally/vertically you could make IsPlayerInArea with a tiny difference between max(x/y) and min(x/y), if it's diagonally I have no clue, maybe IsPlayerInRangeOfPoint with a radius of 1 going all the way from the first bottle to the second bottle?
Reply
#4

There is a couple ways you could do this such a line sphere intersection ray casting another way you could do this.

1.) Get distance between object1, object2
2.) Get distance of player between object1, object2
3.) If the distance of the player to object1 or object2 is greater than the distance between the objects the player can not be between the objects!
4.) Add distance from object1 to object2 together
5.) Subtract the distance between object1 and object2 from that value
6.) Check tolerance to see if player is between objects

Okay here is a test script you can try to see how this works.

Код:
#include <a_samp>

public OnFilterScriptInit()
{
	CreateObject(3337, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0);
    CreateObject(3337, 0.0, 10.0, 3.0, 0.0, 0.0, 0.0);
	return 1;
}

new Float:Object1[3] = { 0.0, 0.0, 3.0 };
new Float:Object2[3] = { 0.0, 10.0, 3.0 };


public OnPlayerUpdate(playerid)
{
	new Float:sphere[3];
	GetPlayerPos(playerid, sphere[0], sphere[1], sphere[2]);
	if(RaySphere(Object1, Object2, sphere, 1.0)) SendClientMessage(playerid, -1, "Between objects!");
	return 1;
}


Float:GetDistance(Float:x1,Float:y1,Float:z1, Float:x2,Float:y2,Float:z2)
{
	return floatsqroot(floatpower(floatabs(floatsub(x2,x1)),2)+floatpower(floatabs(floatsub(y2,y1)),2)+floatpower(floatabs(floatsub(z2,z1)),2));
}

RaySphere(Float:p1[3],Float:p2[3],Float:sc[3],Float:r)
{
	new Float:dist, Float:sdist1, Float:sdist2;
	dist = GetDistance(p1[0], p1[1], p1[2], p2[0], p2[1], p2[2]);
    sdist1 = GetDistance(sc[0], sc[1], sc[2], p1[0], p1[1], p1[2]);
    sdist2 = GetDistance(sc[0], sc[1], sc[2], p2[0], p2[1], p2[2]);
    
	// Make sure player is between the points if so check if the sphere intersects
    if(dist > sdist1 && dist > sdist2)
	{
		new Float:a, Float:b, Float:c, Float:bb4ac, Float:dp[3];
		dp[0] = p2[0] - p1[0];
		dp[1] = p2[1] - p1[1];
		dp[2] = p2[2] - p1[2];
		a = dp[0] * dp[0] + dp[1] * dp[1] + dp[2] * dp[2];
		b = 2 * (dp[0] * (p1[0] - sc[0]) + dp[1] * (p1[1] - sc[1]) + dp[2] * (p1[2] - sc[2]));
		c = sc[0] * sc[0] + sc[1] * sc[1] + sc[2] * sc[2];
		c += p1[0] * p1[0] + p1[1] * p1[1] + p1[2] * p1[2];
		c -= 2 * (sc[0] * p1[0] + sc[1] * p1[1] + sc[2] * p1[2]);
		c -= r * r;
		bb4ac = b * b - 4 * a * c;
		if(bb4ac < 0) return 0;
		return 1;
	}
	return 0;
}
Reply
#5

Quote:
Originally Posted by JaydenJason
Посмотреть сообщение
If the two bottles are aligned horizontally/vertically you could make IsPlayerInArea with a tiny difference between max(x/y) and min(x/y), if it's diagonally I have no clue, maybe IsPlayerInRangeOfPoint with a radius of 1 going all the way from the first bottle to the second bottle?
Yeah that's a bit helpful thanks anyway

Quote:
Originally Posted by Pottus
Посмотреть сообщение
There is a couple ways you could do this such a line sphere intersection ray casting another way you could do this.

1.) Get distance between object1, object2
2.) Get distance of player between object1, object2
3.) If the distance of the player to object1 or object2 is greater than the distance between the objects the player can not be between the objects!
4.) Add distance from object1 to object2 together
5.) Subtract the distance between object1 and object2 from that value
6.) Check tolerance to see if player is between objects

Okay here is a test script you can try to see how this works.

Код:
#include <a_samp>

public OnFilterScriptInit()
{
	CreateObject(3337, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0);
    CreateObject(3337, 0.0, 10.0, 3.0, 0.0, 0.0, 0.0);
	return 1;
}

new Float:Object1[3] = { 0.0, 0.0, 3.0 };
new Float:Object2[3] = { 0.0, 10.0, 3.0 };


public OnPlayerUpdate(playerid)
{
	new Float:sphere[3];
	GetPlayerPos(playerid, sphere[0], sphere[1], sphere[2]);
	if(RaySphere(Object1, Object2, sphere, 1.0)) SendClientMessage(playerid, -1, "Between objects!");
	return 1;
}


Float:GetDistance(Float:x1,Float:y1,Float:z1, Float:x2,Float:y2,Float:z2)
{
	return floatsqroot(floatpower(floatabs(floatsub(x2,x1)),2)+floatpower(floatabs(floatsub(y2,y1)),2)+floatpower(floatabs(floatsub(z2,z1)),2));
}

RaySphere(Float:p1[3],Float:p2[3],Float:sc[3],Float:r)
{
	new Float:dist, Float:sdist1, Float:sdist2;
	dist = GetDistance(p1[0], p1[1], p1[2], p2[0], p2[1], p2[2]);
    sdist1 = GetDistance(sc[0], sc[1], sc[2], p1[0], p1[1], p1[2]);
    sdist2 = GetDistance(sc[0], sc[1], sc[2], p2[0], p2[1], p2[2]);
    
	// Make sure player is between the points if so check if the sphere intersects
    if(dist > sdist1 && dist > sdist2)
	{
		new Float:a, Float:b, Float:c, Float:bb4ac, Float:dp[3];
		dp[0] = p2[0] - p1[0];
		dp[1] = p2[1] - p1[1];
		dp[2] = p2[2] - p1[2];
		a = dp[0] * dp[0] + dp[1] * dp[1] + dp[2] * dp[2];
		b = 2 * (dp[0] * (p1[0] - sc[0]) + dp[1] * (p1[1] - sc[1]) + dp[2] * (p1[2] - sc[2]));
		c = sc[0] * sc[0] + sc[1] * sc[1] + sc[2] * sc[2];
		c += p1[0] * p1[0] + p1[1] * p1[1] + p1[2] * p1[2];
		c -= 2 * (sc[0] * p1[0] + sc[1] * p1[1] + sc[2] * p1[2]);
		c -= r * r;
		bb4ac = b * b - 4 * a * c;
		if(bb4ac < 0) return 0;
		return 1;
	}
	return 0;
}
You got it mate, I really like your idea and appreciate your help, +1.
For now I will test the ray sphere method as shown in your script (y)
Reply
#6

You could also use angles for a approximation

Both objects are imaginary viewing each other, if X and Y are in both "viewing angles" of the objects the player is between them (the viewing angle is given by the parameter degrees * 2)

Resulting that the detection area looks like a rhombus obj1<>obj2
pawn Код:
stock IsBetweenXY(Float: X, Float: Y, Float: X1, Float: Y1, Float: X2, Float: Y2, Float: deg = 5.0) {
    return (
        (-deg <= (atan2(X2 - X1, Y2 - Y1) - atan2(X - X1, Y - Y1)) <= deg) &&
        (-deg <= (atan2(X1 - X2, Y1 - Y2) - atan2(X - X2, Y - Y2)) <= deg)
    );
}
Reply
#7

That is pretty clever but how do it as a 3D check?
Reply
#8

Similar although didn't test that
pawn Код:
stock IsBetweenXYZ(Float: X, Float: Y, Float: Z, Float: X1, Float: Y1, Float: Z1, Float: X2, Float: Y2, Float: Z2, Float: deg = 5.0) {
    new
        Float: rZ = atan((Z2 - Z1) / VectorSize(X2 - X1, Y2 - Y1, 0.0))
    ;
    return (
        (-deg <= (atan2(X2 - X1, Y2 - Y1) - atan2(X - X1, Y - Y1)) <= deg) &&
        (-deg <= (atan2(X1 - X2, Y1 - Y2) - atan2(X - X2, Y - Y2)) <= deg) &&
        (-deg <= (rZ - atan((Z - Z1) / VectorSize(X - X1, Y - Y1, 0.0))) <= deg) &&
        (-deg <= (rZ + atan((Z - Z2) / VectorSize(X - X2, Y - Y2, 0.0))) <= deg)
    );
}
Reply
#9

Cool, I think that checking angles is way better than the line sphere intersection ray casting (although ray casting is more precise), I will test it tomorrow on my computer and see how it works
Reply
#10

I tried it out but I think the rhombus test sucks it doesn't trigger very well when close to the objects.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)