Houge
Member
|
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?
|
|
07-27-2019 11:26 PM |
|