About Store Forum Documentation Contact
Donations:
327$/mo



Post Reply 
Position inside Waypoint
Author Message
Houge Offline
Silver Supporter

Post: #1
Position inside Waypoint
If we are using Waypoints to define/limit areas, sometimes we need to check if the position (of a character) is inside of a Waypoint.

For complex polygons there is an algorithm HERE, and here's the code for EE to use it:

Code:
/******************************************************************************/
/******************************************************************************/
//
struct saWaypointChecker
{
public:
    void init(C UID &waypointID);
    Bool posInside(C Vec2 &pos);
    C UID &waypointID(){    return T._waypointID;    }
    
    C Rect rect(){    return T._waypointRect;    }
    
private:
    volatile Bool _init = false;
    Game::Waypoint
       *_waypoint   = nullptr;
    UID _waypointID = UIDZero;
    Memc<Flt> _constant;
    Memc<Flt> _multiple;
    
    Rect _waypointRect;
}

/******************************************************************************/
/******************************************************************************/
//
void saWaypointChecker::init(C UID &waypointID)
{
    C Flt minMax = 32767.0f;
    
    T._waypoint     = Game::World.findWaypoint(waypointID);
    T._waypointID   = (T._waypoint ? waypointID : UIDZero);
    T._waypointRect = Rect(minMax, minMax, -minMax, -minMax);
    
    // Perform precalculation
    if(T._waypoint)
    {
        Game::Waypoint &wp = *T._waypoint;
        
        T._constant.setNum(wp.points.elms());
        T._multiple.setNum(wp.points.elms());
        
        Int j = wp.points.elms() - 1;

        for(Int i = 0; i < wp.points.elms(); i++)
        {
            if(wp.points[j].pos.z == wp.points[i].pos.z)
            {
                T._constant[i] = wp.points[i].pos.x;
                T._multiple[i] = 0;
            }
            else
            {
                T._constant[i] = wp.points[i].pos.x - (wp.points[i].pos.z * wp.points[j].pos.x) / (wp.points[j].pos.z - wp.points[i].pos.z) +
                                                      (wp.points[i].pos.z * wp.points[i].pos.x) / (wp.points[j].pos.z - wp.points[i].pos.z);
                T._multiple[i] = (wp.points[j].pos.x - wp.points[i].pos.x) / (wp.points[j].pos.z - wp.points[i].pos.z);
            }
            
            j = i;
            
            // Defining bounding Rect
            T._waypointRect.min.x = Min(T._waypointRect.min.x, wp.points[i].pos.x);
            T._waypointRect.min.y = Min(T._waypointRect.min.y, wp.points[i].pos.z);
            
            T._waypointRect.max.x = Max(T._waypointRect.max.x, wp.points[i].pos.x);
            T._waypointRect.max.y = Max(T._waypointRect.max.y, wp.points[i].pos.z);
        }
    }    
    
    T._init = (T._waypoint && T._waypointID != UIDZero);
}

Bool saWaypointChecker::posInside(C Vec2 &pos)
{
    if(!T._init)
    {
        return false;
    }
    
    // First and fastest check
    if(!T._waypointRect.includes(pos))
    {
        return false;
    }
    
    // If position is inside rect, perform more precise check
    if(T._waypoint)
    {
        Game::Waypoint &wp = *T._waypoint;
        Bool oddNodes = false, current = wp.points.last().pos.z > pos.y, previous;
        for(Int i = 0; i < wp.points.elms(); i++)
        {
            previous = current;
            current = wp.points[i].pos.z > pos.y;
            if(current != previous)
            {
                oddNodes ^= (pos.y * T._multiple[i] + T._constant[i] < pos.x);
            }
        }
    
        return oddNodes;
    }
    
    return false;
}

/******************************************************************************/
/******************************************************************************/

the usage is the following (initialization to perform precalculations just once):

Code:
saWaypointChecker wpHandler;

... init just once ...
wpHandler.init(UID(0, 0, 0, 0)); // your Waypoint ID here

... and then check XZ position in any loop ...
if(wpHandler.posInside(pos.xz()))
{
    // do something
}

P.S. Greg, maybe you can move these precalculations to waypoint class and add "Waypoint.Cuts" function? smile
07-27-2019 11:26 PM
Visit this user's website Find all posts by this user Quote this message in a reply
Post Reply