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) |
#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; }
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?
|
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; } |
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)
);
}
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)
);
}