Detecting if an object is within a rectangle
#1

I'm wanting to detect if an object is within a rectangle relative to the players co-ordinates. IsPlayerInRangeOfPoint() can work but it detects within a sphere. I want the range to be more specific about how far to the left and right of the player the object can be and how far forward and back. Seems like it might require some complex mathematical formula to calculate but I wouldn't know where to start. Any ideas?
Reply
#2

A streamer could help you https://sampforum.blast.hk/showthread.php?tid=102865

Код:
native STREAMER_TAG_AREA CreateDynamicRectangle(Float:minx, Float:miny, Float:maxx, Float:maxy, worldid = -1, interiorid = -1, playerid = -1);


native AttachDynamicAreaToPlayer(STREAMER_TAG_AREA areaid, playerid, Float:offsetx = 0.0, Float:offsety = 0.0, Float:offsetz = 0.0);
Reply
#3

Thanks for the help. I'll give it a go. Rep+
Reply
#4

Well there are only 4 points in a rectangle... 'Maximum X coordinate', 'Minimum X coordinate', 'Maximum Y coordinate' and 'Minimum Y coordinate'. Determining the area depends on how you want it to work, if you want it to work based on North-South/East-West then you can easily use the maximum and minimum coordinates as offsets.

PHP код:
new Float:xFloat:yFloat:z;
GetObjectPos(objectidxyz); 
Let's say for example you want the rectangle to be 50 units to the sides, and 20 units to the front and back.

Minimum X coordinate = x - 50.0
Maximum X coordinate = x + 50.0
Minimum Y coordinate = y - 20.0
Maximum Y coordinate = y + 20.0

To check if the object is inside the rectangle:
PHP код:
if((50.0) <= <= (50.0) && (20.0) <= <= (20.0))
{
    
// Object is inside the rectangle
}
else
{
    
// Object is not inside the rectangle

If you want the object to be in terms of the way the player is facing, then you need to use basic trigonometry to adjust the coordinates based on the player's facing angle.
Reply
#5

Yeah as you say I want the co-ordinates to be relative to the facing angle as well. I forgot to mention that part. You wouldn't happen to know how the trigonometry will work would you?
Reply
#6

It really is just basic trigonometry. Sin and Cos are really the only things you need to understand. I try and remember this formula when working with relative coordinates:

PHP код:
OriginX + (sin(angle) * OffsetY cos(angle) * OffsetX);
OriginY + (cos(angle) * OffsetY sin(angle) * OffsetX); 


The red dot in the centre is the player's position or the origin of whatever you're calculating from. The blue dots are the four corners or points of the rectangle, respectively in the order: (minx, miny), (minx, maxy), (maxx, miny), (maxx, maxy).

As SA-MP angles work counter-clockwise, all you have to do beforehand is either subtract the angle from 360 degrees or simply make the angle negative. Here's an example of how you would achieve this:
PHP код:
CMD:test(playeridparams[])
{
    new
        
Float:OffsetX,
        
Float:OffsetY
    
;
    if(
sscanf(params"ff"OffsetXOffsetY))
        return 
SendClientMessage(playerid, -1"USAGE: /test [offset X] [offset Y]");
    new
        
Float:PlayerX// Player's X coordinate (OriginX)
        
Float:PlayerY// Player's Y coordinate (OriginY)
        
Float:PlayerZ,
        
Float:PlayerA// Player's facing angle (angle)
        
Float:Vertices[4][2// The corners/vertices of the rectangle. There are 4 corners with 2 coordinates (X and Y) each, hence the [4][2].
    
;
    
GetPlayerPos(playeridPlayerXPlayerYPlayerZ); // Store the player's position. Z coordinate is only really needed for the objects. It doesn't need to be used in the calculations.
    
GetPlayerFacingAngle(playeridPlayerA); // Store the player's facing angle.
    
new
        
Float:sin floatsin(-PlayerAdegrees), // You don't have to do this, but it saves calculating the same thing over and over and helps readability.
        
Float:cos floatcos(-PlayerAdegrees// Again, not necessary.
    
;
    
// Now for the calculations for each point.
    // Point 1 (MinX, MinY)
    
Vertices[0][0] = PlayerX sin * -OffsetY cos * -OffsetX;
    
Vertices[0][1] = PlayerY cos * -OffsetY sin * -OffsetX;
    
// Point 2 (MinX, MaxY)
    
Vertices[1][0] = PlayerX sin OffsetY cos * -OffsetX;
    
Vertices[1][1] = PlayerY cos OffsetY sin * -OffsetX;
    
// Point 3 (MaxX, MinY)
    
Vertices[2][0] = PlayerX sin * -OffsetY cos OffsetX;
    
Vertices[2][1] = PlayerY cos * -OffsetY sin OffsetX;
    
// Point 4 (MaxX, MaxY)
    
Vertices[3][0] = PlayerX sin OffsetY cos OffsetX;
    
Vertices[3][1] = PlayerY cos OffsetY sin OffsetX;
    
CreateObject(19122Vertices[0][0], Vertices[0][1], PlayerZ0.00.00.0); // Blue
    
CreateObject(19123Vertices[1][0], Vertices[1][1], PlayerZ0.00.00.0); // Green
    
CreateObject(19124Vertices[2][0], Vertices[2][1], PlayerZ0.00.00.0); // Red
    
CreateObject(19125Vertices[3][0], Vertices[3][1], PlayerZ0.00.00.0); // Yellow
    
return 1;

This will place a bollard on each corner of the theoretical rectangle with the offsets that you specify. When working with 'MinX', the X offset is negative, and positive when working with 'MaxX'. When working with 'MinY', the Y offset is negative, and positive when working with 'MaxY'.

In terms of checking whether a certain point is inside that rectangle? Well... that's a whole other issue...
http://math.stackexchange.com/questi...de-a-rectangle
http://mathforum.org/library/drmath/view/54386.html
http://stackoverflow.com/questions/3...in-a-rectangle

Now someone call Nero_3D, he has some work to do with converting this to pawn.
Reply
#7

Wow thanks mate that's really helpful. Getting closer to a full solution. I'll see how far I can get from here. Rep+
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)