1054 lines
30 KiB
C++
1054 lines
30 KiB
C++
#include "CKAll.h"
|
|
#include "NodeGrid.h"
|
|
#include "FollowProblem.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// FollowProblem
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
FollowProblem::FollowProblem(CKMessageManager *messageManager, CKAttributeManager *attributManager, NodeGrid *arrayNodeGrid)
|
|
{
|
|
m_MessageManager = messageManager;
|
|
m_AttributManager = attributManager;
|
|
m_ArrayNodeGrid = arrayNodeGrid;
|
|
m_Message[0] = m_MessageManager->AddMessageType("Joy_Up");
|
|
m_Message[1] = m_MessageManager->AddMessageType("Joy_Down");
|
|
m_Message[2] = m_MessageManager->AddMessageType("Joy_Left");
|
|
m_Message[3] = m_MessageManager->AddMessageType("Joy_Right");
|
|
m_Invisible = FALSE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// ~FollowProblem
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
FollowProblem::~FollowProblem()
|
|
{
|
|
// Clear the path
|
|
int size = m_Path.m_ArraySubPath.Size();
|
|
for (int i = 0; i < size; i++)
|
|
delete m_Path.m_ArraySubPath[i];
|
|
m_Path.m_ArraySubPath.Clear();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Set
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::Set(FollowStruct *followStruct, Path *path, CKAttributeType attrType)
|
|
{
|
|
if (followStruct->beh->GetOutputCount() == 7)
|
|
m_ManageTeleporter = TRUE;
|
|
else
|
|
m_ManageTeleporter = FALSE;
|
|
m_Beh = followStruct->beh;
|
|
m_Target = followStruct->target;
|
|
m_Character = (CKCharacter *)m_Target;
|
|
m_Path.CopyAndErase(*path);
|
|
m_PathID = followStruct->followPathID;
|
|
if (followStruct->minDistanceFactor > 1)
|
|
m_MinDistanceFactor = 1;
|
|
else if (followStruct->minDistanceFactor < 0)
|
|
m_MinDistanceFactor = 0.0001f;
|
|
else
|
|
m_MinDistanceFactor = followStruct->minDistanceFactor;
|
|
m_LimitAngleCos = XAbs(cosf(followStruct->limitAngle));
|
|
m_Fuzzyness = XAbs(followStruct->fuzzyness);
|
|
if (m_Fuzzyness > 1)
|
|
m_Fuzzyness = 1;
|
|
m_Fuzzyness2 = 0.5f*m_Fuzzyness;
|
|
m_Fuzzyness /= RAND_MAX;
|
|
m_Pingpong = followStruct->pingpong;
|
|
if (followStruct->maxBlockedTime >= 0)
|
|
m_MaxBlockedTime = followStruct->maxBlockedTime;
|
|
else
|
|
m_MaxBlockedTime = 0;
|
|
m_DistanceBlocked = XAbs(followStruct->distanceBlocked);
|
|
|
|
m_AttrType = attrType;
|
|
CKParameterOut *pout = m_Target->GetAttributeParameter(attrType);
|
|
if (pout)
|
|
{
|
|
CK_ID *paramids = (CK_ID *)pout->GetReadDataPtr();
|
|
((CKParameterOut *)m_MessageManager->CKGetObject(paramids[0]))->GetValue(&m_ColisionFilter);
|
|
((CKParameterOut *)m_MessageManager->CKGetObject(paramids[1]))->GetValue(&m_RadiusColision);
|
|
((CKParameterOut *)m_MessageManager->CKGetObject(paramids[2]))->GetValue(&m_RadiusAvoid);
|
|
}
|
|
else
|
|
{
|
|
m_ColisionFilter = 0;
|
|
m_RadiusColision = -1;
|
|
m_RadiusAvoid = 1;
|
|
}
|
|
|
|
if (followStruct->enterTele >= 0)
|
|
m_EnterTeleTime = followStruct->enterTele;
|
|
else
|
|
m_EnterTeleTime = 0;
|
|
if (followStruct->travelTele)
|
|
m_TravelTeleTime = followStruct->travelTele;
|
|
else
|
|
m_TravelTeleTime = 0;
|
|
if (followStruct->exitTele)
|
|
m_ExitTeleTime = followStruct->exitTele;
|
|
else
|
|
m_ExitTeleTime = 0;
|
|
m_State = on;
|
|
m_StateFunction = ::ComputeDir;
|
|
m_TestTurnAngleCount = 0;
|
|
m_LinkerObs = path->m_LinkerObs;
|
|
|
|
// Set align function.
|
|
switch(followStruct->direction)
|
|
{
|
|
case 1:
|
|
m_AlignFunction = AlignOnPath1;
|
|
break;
|
|
case 2:
|
|
m_AlignFunction = AlignOnPath2;
|
|
break;
|
|
case 3:
|
|
m_AlignFunction = AlignOnPath3;
|
|
break;
|
|
case 4:
|
|
m_AlignFunction = AlignOnPath4;
|
|
break;
|
|
case 5:
|
|
m_AlignFunction = AlignOnPath5;
|
|
break;
|
|
case 6:
|
|
m_AlignFunction = AlignOnPath6;
|
|
break;
|
|
}
|
|
m_TimeBlocked.Reset();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Reset
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::Reset()
|
|
{
|
|
m_State = finish;
|
|
m_StateFunction = ::ComputeDir;
|
|
|
|
// Clear the path.
|
|
m_Path.Clear();
|
|
|
|
if (m_Invisible)
|
|
{
|
|
m_Invisible = FALSE;
|
|
m_Target->Show(CKSHOW);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Orient
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::FirstOrient(int firstSubPath)
|
|
{
|
|
// Get path information.
|
|
m_NumSubPath = m_Path.NbSubPath()-1-firstSubPath;
|
|
m_SubPath = m_Path.GetSubPath(m_NumSubPath);
|
|
if (m_NumSubPath)
|
|
m_NextSubPath = m_Path.GetSubPath(m_NumSubPath-1);
|
|
m_TotalPoint = m_SubPath->NbCase();
|
|
|
|
// Get usefull information.
|
|
m_Grid = m_SubPath->m_Grid;
|
|
m_Layer = m_Grid->GetLayer(m_Path.m_ObstacleLayer);
|
|
m_Grid->GetScale(&m_GridScale);
|
|
m_GridScale.y = 0;
|
|
m_RadiusCgrid = m_RadiusColision/m_GridScale.x;
|
|
m_MinDistance = (float)(Magnitude(m_GridScale)*m_MinDistanceFactor);
|
|
m_W = m_Grid->GetWidth();
|
|
m_L = m_Grid->GetLength();
|
|
|
|
// Get current character position.
|
|
m_Charac = m_Character->GetFloorReferenceObject();
|
|
if (!m_Charac)
|
|
m_Charac = m_Character->GetRootBodyPart();
|
|
m_Charac->GetPosition(&m_RealPosition);
|
|
m_Position = m_RealPosition;
|
|
m_Position.y = 0;
|
|
|
|
// Set Old Pos.
|
|
m_OldPosition = m_Position;
|
|
m_PosToMoveFrom = m_Position;
|
|
|
|
m_NumPoint = 1;
|
|
|
|
// Calcul real dir.
|
|
PointAndDir2();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// CalculDirection
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::CalculDirection()
|
|
{
|
|
if (m_State == off)
|
|
return;
|
|
|
|
// Orient the target.
|
|
m_StateFunction(this);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// CorrectDirection
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::CorrectDirection()
|
|
{
|
|
if (m_State != on && m_State != slow)
|
|
return;
|
|
|
|
// Reset to normal.
|
|
m_MoveFunction = ::TurnAndUp;
|
|
m_State = on;
|
|
|
|
// m_RadiusColision == -1 means no path finding colision attribut
|
|
if (m_RadiusColision == -1)
|
|
return;
|
|
|
|
FollowProblem *fpColision, *fpAvoid ;
|
|
CK3dEntity *entCollision, *entAvoid;
|
|
float entRadiusCollision;
|
|
|
|
// Scan for 3dentities obstacles.
|
|
if (!ScanRadius(fpColision, fpAvoid))
|
|
ScanRadius(entCollision, entAvoid, entRadiusCollision);
|
|
|
|
// Manage collision.
|
|
if (fpColision)
|
|
{
|
|
RejectByTarget(fpColision);
|
|
// Activate collision output
|
|
m_Beh->ActivateOutput(2);
|
|
// Write collions parameter output
|
|
m_Beh->SetOutputParameterObject(0, fpColision->m_Target);
|
|
}
|
|
else if (entCollision)
|
|
{
|
|
RejectByTarget(entCollision, entRadiusCollision);
|
|
// Activate collision output
|
|
m_Beh->ActivateOutput(2);
|
|
// Write collions parameter output
|
|
m_Beh->SetOutputParameterObject(0, entCollision);
|
|
}
|
|
|
|
// Manage avoiding
|
|
if (fpAvoid)
|
|
{
|
|
int pos, dir, speed;
|
|
AnalyseTarget(fpAvoid, pos, dir, speed);
|
|
AvoidTarget(fpAvoid, pos, dir, speed);
|
|
// Activate avoid.
|
|
m_Beh->ActivateOutput(3);
|
|
// Write avoid parameter output.
|
|
m_Beh->SetOutputParameterObject(1, fpAvoid->m_Target);
|
|
}
|
|
else if (entAvoid)
|
|
{
|
|
AvoidTarget(entAvoid, entRadiusCollision);
|
|
// Activate avoid.
|
|
m_Beh->ActivateOutput(3);
|
|
// Write avoid parameter output.
|
|
m_Beh->SetOutputParameterObject(1, entAvoid);
|
|
}
|
|
|
|
// Check for Layer obstacles.
|
|
RejectByObstacle();
|
|
|
|
// Detect blocked situation;
|
|
DetectBlocked();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Move
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::Move()
|
|
{
|
|
m_MoveFunction(this);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Up
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::ComputeDir()
|
|
{
|
|
// Get current character position.
|
|
m_Charac = m_Character->GetFloorReferenceObject();
|
|
if (!m_Charac)
|
|
m_Charac = m_Character->GetRootBodyPart();
|
|
m_Charac->GetPosition(&m_RealPosition);
|
|
m_Position = m_RealPosition;
|
|
m_Position.y = 0;
|
|
|
|
VxVector pt1;
|
|
VxVector pt2;
|
|
int a = m_SubPath->GetCase(0);
|
|
int b = m_SubPath->GetCase(1);
|
|
m_Dt = div(a, m_W);
|
|
m_NextY = m_Dt.quot;
|
|
m_NextX = m_Dt.rem;
|
|
m_Grid->Get3dPosFrom2dCoords(&pt1, m_NextX, m_NextY);
|
|
m_Dt = div(b, m_W);
|
|
m_NextY = m_Dt.quot;
|
|
m_NextX = m_Dt.rem;
|
|
m_Grid->Get3dPosFrom2dCoords(&pt2, m_NextX, m_NextY);
|
|
|
|
// Recalculate (if grid is moving !)
|
|
if (m_Grid->GetMoveableFlags() & VX_MOVEABLE_HASMOVED)
|
|
PointAndDir();
|
|
|
|
m_Distance = Magnitude((m_NextPoint-m_Position));
|
|
if (m_Distance < m_MinDistance)
|
|
{
|
|
// Save Type case.
|
|
if (m_SubPath->m_LinkerStart)
|
|
m_OldTypeCase = m_SubPath->m_LinkerStart->m_TypeCase;
|
|
else
|
|
m_OldTypeCase = tc_normal;
|
|
|
|
// Next subpath point.
|
|
++m_NumPoint;
|
|
if (m_NumPoint == m_TotalPoint)
|
|
{
|
|
// Next subpath.
|
|
if (--m_NumSubPath < 0 || m_OldTypeCase == tc_tele2)
|
|
{
|
|
if (m_Pingpong)
|
|
{
|
|
m_Path.Inverse();
|
|
if (m_OldTypeCase == tc_tele2)
|
|
FirstOrient(++m_NumSubPath);
|
|
else
|
|
FirstOrient(0);
|
|
return;
|
|
}
|
|
// The path is finish.
|
|
m_State = finish;
|
|
return;
|
|
}
|
|
|
|
// Change subpath.
|
|
m_SubPath = m_Path.GetSubPath(m_NumSubPath);
|
|
if (m_NumSubPath)
|
|
m_NextSubPath = m_Path.GetSubPath(m_NumSubPath-1);
|
|
m_TotalPoint = m_SubPath->NbCase();
|
|
|
|
// Get usefull information.
|
|
m_Grid = m_SubPath->m_Grid;
|
|
m_Layer = m_Grid->GetLayer(m_Path.m_ObstacleLayer);
|
|
m_Grid->GetScale(&m_GridScale);
|
|
m_GridScale.y = 0;
|
|
m_RadiusCgrid = m_RadiusColision/m_GridScale.x;
|
|
m_MinDistance = (float)(Magnitude(m_GridScale)*m_MinDistanceFactor);
|
|
m_W = m_Grid->GetWidth();
|
|
m_L = m_Grid->GetLength();
|
|
|
|
if (m_OldTypeCase != tc_door)
|
|
{
|
|
m_NumPoint = 1;
|
|
|
|
// Set new target position (teleportation).
|
|
m_Dt = div(m_SubPath->GetCase(0), m_W);
|
|
m_NextY = m_Dt.quot;
|
|
m_NextX = m_Dt.rem;
|
|
m_Grid->Get3dPosFrom2dCoords(&m_Position, m_NextX, m_NextY);
|
|
|
|
// Manage teleporter wait.
|
|
m_TimeTele.Reset();
|
|
m_State = entertele;
|
|
m_StateFunction = ::EnterTele;
|
|
if (m_ManageTeleporter)
|
|
m_Beh->ActivateOutput(4);
|
|
EnterTele();
|
|
return;
|
|
}
|
|
else
|
|
m_NumPoint = 0;
|
|
}
|
|
PointAndDir();
|
|
}
|
|
|
|
// Set the new direction.
|
|
// In fact, if we haven't changing the subpath point, the new direction shouldn't
|
|
// change but if character is moved by other thing we must recalculate the direction.
|
|
|
|
VxVector vector = m_Position - m_NextPointFuzzy;
|
|
VxVector point = m_NextPointFuzzy + (DotProduct(vector, m_RealDir)+m_GridScale.x)*m_RealDir;
|
|
point.y = 0;
|
|
|
|
if (Magnitude(m_NextPointFuzzy-point) < m_Distance2Point)
|
|
m_Dir = point - m_Position;
|
|
else
|
|
m_Dir = m_NextPoint - m_Position;
|
|
m_Dir.y = 0;
|
|
m_Dir.Normalize();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// PointAndDir
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::PointAndDir()
|
|
{
|
|
m_NextPointFuzzy = m_NextPoint;
|
|
|
|
// Set new next point.
|
|
if (!m_NumSubPath && (m_NumPoint == m_TotalPoint-1))
|
|
{
|
|
VxVector lastPoint;
|
|
m_Grid->InverseTransform(&lastPoint, &m_Path.m_LastPoint);
|
|
lastPoint.y = 0;
|
|
m_Grid->Transform(&m_NextPoint, &lastPoint);
|
|
}
|
|
else
|
|
{
|
|
m_Dt = div(m_SubPath->GetCase(m_NumPoint), m_W);
|
|
m_NextY = m_Dt.quot;
|
|
m_NextX = m_Dt.rem;
|
|
m_Grid->Get3dPosFrom2dCoords(&m_NextPoint, m_NextX, m_NextY);
|
|
}
|
|
if (m_Fuzzyness)
|
|
{
|
|
// Add random in nextpoint.
|
|
m_Grid->InverseTransform(&m_NextPoint, &m_NextPoint);
|
|
m_NextPoint.x += ((float)rand()*m_Fuzzyness)-m_Fuzzyness2;
|
|
m_NextPoint.z += ((float)rand()*m_Fuzzyness)-m_Fuzzyness2;
|
|
m_Grid->Transform(&m_NextPoint, &m_NextPoint);
|
|
}
|
|
m_NextPoint.y = 0;
|
|
|
|
// Calcul the real direction.
|
|
m_RealDir = m_NextPoint - m_NextPointFuzzy;
|
|
m_Distance2Point = Magnitude(m_RealDir);
|
|
m_RealDir.y = 0;
|
|
m_RealDir.Normalize();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// PointAndDir2
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::PointAndDir2()
|
|
{
|
|
// Set new next point.
|
|
m_Dt = div(m_SubPath->GetCase(1), m_W);
|
|
m_NextY = m_Dt.quot;
|
|
m_NextX = m_Dt.rem;
|
|
m_Grid->Get3dPosFrom2dCoords(&m_NextPoint, m_NextX, m_NextY);
|
|
if (m_Fuzzyness)
|
|
{
|
|
// Add random in nextpoint.
|
|
m_Grid->InverseTransform(&m_NextPoint, &m_NextPoint);
|
|
m_NextPoint.x += ((float)rand()*m_Fuzzyness)-m_Fuzzyness2;
|
|
m_NextPoint.z += ((float)rand()*m_Fuzzyness)-m_Fuzzyness2;
|
|
m_Grid->Transform(&m_NextPoint, &m_NextPoint);
|
|
}
|
|
m_NextPoint.y = 0;
|
|
|
|
m_NextPointFuzzy = m_Position;
|
|
|
|
// Calcul the real direction.
|
|
m_RealDir = m_NextPoint - m_NextPointFuzzy;
|
|
m_Distance2Point = Magnitude(m_RealDir);
|
|
m_RealDir.y = 0;
|
|
m_RealDir.Normalize();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// EnterTele
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::EnterTele()
|
|
{
|
|
if (m_NextSubPath->m_LinkerStart->m_Occupy)
|
|
m_TimeTele.Reset();
|
|
if (m_TimeTele.Current() < m_EnterTeleTime)
|
|
return;
|
|
m_State = traveltele;
|
|
m_StateFunction = ::TravelTele;
|
|
m_Target->Show(CKHIERARCHICALHIDE);
|
|
m_Invisible = TRUE;
|
|
m_TimeTele.Reset();
|
|
if (m_ManageTeleporter)
|
|
m_Beh->ActivateOutput(5);
|
|
|
|
// Mark linker as occuped.
|
|
m_NextSubPath->m_LinkerStart->m_Occupy = TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TravelTele
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::TravelTele()
|
|
{
|
|
if (m_TimeTele.Current() < m_TravelTeleTime)
|
|
return;
|
|
m_State = exittele;
|
|
m_StateFunction = ::ExitTele;
|
|
m_Character->SetPosition(&m_Position);
|
|
m_RealPosition = m_Position;
|
|
m_Target->Show(CKSHOW);
|
|
m_Invisible = FALSE;
|
|
m_TimeTele.Reset();
|
|
if (m_ManageTeleporter)
|
|
m_Beh->ActivateOutput(6);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// ExitTele
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::ExitTele()
|
|
{
|
|
if (m_TimeTele.Current() < m_ExitTeleTime)
|
|
return;
|
|
|
|
// Mark linker as unoccuped.
|
|
m_NextSubPath->m_LinkerStart->m_Occupy = FALSE;
|
|
m_State = on;
|
|
m_StateFunction = ::ComputeDir;
|
|
PointAndDir2();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// CheckLayerObstacle
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::RejectByObstacle()
|
|
{
|
|
if (!m_NumPoint)
|
|
// We are betwwenn two grid so we don't check for obstacle.
|
|
return;
|
|
VxVector posGrid;
|
|
VxVector min,max;
|
|
VxVector vector;
|
|
float dist = 999999999.0f;
|
|
float dist2;
|
|
int sI = -1;
|
|
int sJ;
|
|
int val;
|
|
|
|
m_Grid->InverseTransform(&posGrid, &m_RealPosition);
|
|
min.x = posGrid.x-m_RadiusCgrid-1;
|
|
min.z = posGrid.z-m_RadiusCgrid-1;
|
|
min.y = 0;
|
|
max.x = posGrid.x+m_RadiusCgrid+1;
|
|
max.z = posGrid.z+m_RadiusCgrid+1;
|
|
max.y = 0;
|
|
if (min.x < 0) min.x = 0;
|
|
if (max.x >= m_W) max.x = (float)m_W-1;
|
|
if (min.z < 0) min.z = 0;
|
|
if (max.z >= m_L) max.z = (float)m_L-1;
|
|
for (int i = (int)min.x; i <= (int)max.x; ++i)
|
|
for (int j = (int)min.z; j <= (int)max.z; ++j)
|
|
{
|
|
val = 0;
|
|
if (m_Layer)
|
|
m_Layer->GetValue(i, j, &val);
|
|
// Check Layer Obstacle.
|
|
if (val > m_Path.m_ObstacleThreshold)
|
|
{
|
|
if ((dist2 = Magnitude(posGrid-VxVector(i+0.5f,0,j+0.5f))) < dist)
|
|
{
|
|
sI = i;
|
|
sJ = j;
|
|
dist = dist2;
|
|
}
|
|
}
|
|
// Check Linker Obstacle.
|
|
else if(m_LinkerObs)
|
|
{
|
|
int index = j*m_W+i;
|
|
NodeLinker *linker = m_ArrayNodeGrid[index].m_LinkerObs[m_SubPath->m_NumGrid];
|
|
if (linker && linker->m_TypeCase != tc_door && !(index == m_SubPath->GetCase(0) || index == m_SubPath->GetCase(m_TotalPoint-1)))
|
|
if ((dist2 = Magnitude(posGrid-VxVector(i+0.5f,0,j+0.5f))) < dist)
|
|
{
|
|
sI = i;
|
|
sJ = j;
|
|
dist = dist2;
|
|
}
|
|
}
|
|
}
|
|
if (sI != -1)
|
|
{
|
|
VxVector trans;
|
|
float p,q,y;
|
|
|
|
vector = posGrid-VxVector(sI+0.5f,0,sJ+0.5f);
|
|
vector.Normalize();
|
|
if (vector.x)
|
|
{
|
|
p = vector.z/vector.x;
|
|
q = sJ+0.5f-p*(sI+0.5f);
|
|
if (vector.x > 0)
|
|
y = p*(sI+1.0f)+q;
|
|
else
|
|
y = p*sI+q;
|
|
}
|
|
else
|
|
y = sJ+2.0f;
|
|
if (y > sJ+1 || y < sJ)
|
|
{
|
|
// Cut x.
|
|
if (vector.z > 0)
|
|
{
|
|
trans.z = posGrid.z-(sJ+1);
|
|
if (trans.z >= m_RadiusCgrid) return;
|
|
trans.z = m_RadiusCgrid-trans.z;
|
|
}
|
|
else
|
|
{
|
|
trans.z = sJ-posGrid.z;
|
|
if (trans.z >= m_RadiusCgrid) return;
|
|
trans.z = -m_RadiusCgrid+trans.z;
|
|
}
|
|
trans.x = 0;
|
|
}
|
|
else
|
|
{
|
|
// Cut z.
|
|
if (vector.x > 0)
|
|
{
|
|
trans.x = posGrid.x-(sI+1);
|
|
if (trans.x >= m_RadiusCgrid) return;
|
|
trans.x = m_RadiusCgrid-trans.x;
|
|
}
|
|
else
|
|
{
|
|
trans.x = sI-posGrid.x;
|
|
if (trans.x >= m_RadiusCgrid) return;
|
|
trans.x = -m_RadiusCgrid+trans.x;
|
|
}
|
|
trans.z = 0;
|
|
}
|
|
trans.y = 0;
|
|
m_Character->Translate(&trans, m_Grid);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// ScanRadius
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
CKBOOL FollowProblem::ScanRadius(FollowProblem *&fpCollision, FollowProblem *&fpAvoid)
|
|
{
|
|
fpCollision = 0;
|
|
fpAvoid = 0;
|
|
if (!m_ColisionFilter)
|
|
return FALSE;
|
|
|
|
FollowProblem *fp ;
|
|
int size = m_ArrayFollowProblem->Size();
|
|
float distance;
|
|
|
|
// Search the follower target.
|
|
for (int i = 0; i < size; ++i)
|
|
{
|
|
fp = (*m_ArrayFollowProblem)[i];
|
|
if (fp->m_Grid != m_Grid || fp->m_Target == m_Target) continue;
|
|
|
|
// Read PF Colision attribut.
|
|
if (!(fp->m_ColisionFilter & m_ColisionFilter)) continue;
|
|
|
|
// Check distance.
|
|
distance = Magnitude(fp->m_Position - m_Position);
|
|
if (distance <= m_RadiusColision+fp->m_RadiusColision)
|
|
fpCollision = fp;
|
|
if (distance <= m_RadiusAvoid+fp->m_RadiusColision)
|
|
fpAvoid = fp;
|
|
if (fpCollision && fpAvoid)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// ScanRadius
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
CKBOOL FollowProblem::ScanRadius(CK3dEntity *&entCollision, CK3dEntity *&entAvoid, float &entRadiusCollision)
|
|
{
|
|
entCollision = 0;
|
|
entAvoid = 0;
|
|
if (!m_ColisionFilter)
|
|
return FALSE;
|
|
|
|
// Search the "attributed" target.
|
|
const XObjectPointerArray& array = m_AttributManager->GetAttributeListPtr(m_AttrType);
|
|
VxVector pos;
|
|
float distance;
|
|
int colisionFilter;
|
|
|
|
for (CKObject **it = array.Begin(); it != array.End(); ++it)
|
|
{
|
|
CK3dEntity *ent = (CK3dEntity *)*it;
|
|
if (m_Target == ent) continue;
|
|
CKParameterOut *pout = ent->GetAttributeParameter(m_AttrType);
|
|
if (pout)
|
|
{
|
|
CK_ID *paramids = (CK_ID *)pout->GetReadDataPtr();
|
|
((CKParameterOut *)m_MessageManager->CKGetObject(paramids[0]))->GetValue(&colisionFilter);
|
|
if (colisionFilter & m_ColisionFilter)
|
|
{
|
|
((CKParameterOut *)m_MessageManager->CKGetObject(paramids[1]))->GetValue(&entRadiusCollision);
|
|
|
|
// Check distance.
|
|
ent->GetPosition(&pos);
|
|
pos.y = 0;
|
|
distance = Magnitude(pos - m_Position);
|
|
if (distance <= m_RadiusColision+entRadiusCollision)
|
|
entCollision = ent;
|
|
if (distance <= m_RadiusAvoid+entRadiusCollision)
|
|
entAvoid = ent;
|
|
if (entCollision && entAvoid)
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// AnalyseTarget
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::AnalyseTarget(FollowProblem *fp, int &pos, int &dir, int &speed)
|
|
{
|
|
VxVector perpDir;
|
|
VxVector perpDirFp;
|
|
perpDir.x = m_Dir1.z;
|
|
perpDir.z = -m_Dir1.x;
|
|
perpDir.y = 0;
|
|
m_DirFP = fp->m_Position-m_Position;
|
|
m_DirFP.y = 0;
|
|
m_DirFP.Normalize();
|
|
perpDirFp.x = -m_DirFP.z;
|
|
perpDirFp.z = m_DirFP.x;
|
|
perpDirFp.y = 0;
|
|
float angleP1 = DotProduct(m_Dir1, m_DirFP);
|
|
float angleP2 = DotProduct(perpDirFp, fp->m_Dir1);
|
|
float angleD1 = DotProduct(m_Dir1, fp->m_Dir1);
|
|
float angleD2 = DotProduct(perpDir, fp->m_Dir1);
|
|
float speed1,speed2;
|
|
|
|
// Get position between this and fp.
|
|
if (angleP2 < 0)
|
|
pos = 0;
|
|
else
|
|
pos = 1;
|
|
if (angleP1 < -0.707)
|
|
pos += 6;
|
|
else if (angleP1 < 0)
|
|
pos += 4;
|
|
else if (angleP1 < 0.707)
|
|
pos += 2;
|
|
|
|
// Get direction between this and fp.
|
|
if (angleD2 > 0)
|
|
dir = 0;
|
|
else
|
|
dir = 1;
|
|
if (angleD1 < -0.707)
|
|
dir += 6;
|
|
else if (angleD1 < 0)
|
|
dir += 4;
|
|
else if (angleD1 < 0.707)
|
|
dir += 2;
|
|
|
|
// Calcul speed.
|
|
speed1 = Magnitude(m_Position-m_OldPosition);
|
|
speed2 = Magnitude(fp->m_Position-fp->m_OldPosition);
|
|
if (XAbs(speed1-speed2) < 0.001)
|
|
speed = 0;
|
|
else if (speed2 > speed1)
|
|
speed = 1;
|
|
else
|
|
speed = -1;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// RejectByTarget
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::RejectByTarget(FollowProblem *fp)
|
|
{
|
|
VxVector corect;
|
|
float factor;
|
|
|
|
// Calcul corect.
|
|
corect = m_Position-fp->m_Position;
|
|
corect.y = 0;
|
|
factor = m_RadiusColision+fp->m_RadiusColision-Magnitude(corect);
|
|
corect.y = 0;
|
|
corect.Normalize();
|
|
corect *= factor;
|
|
|
|
// Corect character pos.
|
|
m_Character->Translate(&corect);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// RejectByTarget
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::RejectByTarget(CK3dEntity *ent, float entRadiusCollision)
|
|
{
|
|
VxVector pos;
|
|
VxVector corect;
|
|
float factor;
|
|
|
|
ent->GetPosition(&pos);
|
|
pos.y = 0;
|
|
|
|
// Calcul corect.
|
|
corect = m_Position-pos;
|
|
corect.y = 0;
|
|
factor = m_RadiusColision+entRadiusCollision-Magnitude(corect);
|
|
corect.Normalize();
|
|
corect *= factor;
|
|
|
|
// Corect character pos.
|
|
m_Character->Translate(&corect);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// AvoidTarget
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::AvoidTarget(FollowProblem *fp, int pos, int dir, int speed)
|
|
{
|
|
|
|
if (pos <= 3)
|
|
{
|
|
// Obstacle is in the front.
|
|
if (dir > 2)
|
|
{
|
|
// Change direction.
|
|
if (pos & 1)
|
|
// Rigth.
|
|
m_Dir = m_Dir2;
|
|
else
|
|
// Left.
|
|
m_Dir = -m_Dir2;
|
|
|
|
m_TestTurnAngleCount = 10;
|
|
m_MoveFunction = ::TurnAndUp2;
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// AvoidTarget
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::AvoidTarget(CK3dEntity *ent, float entRadiusCollision)
|
|
{
|
|
VxVector posEnt;
|
|
VxVector dirEnt;
|
|
|
|
ent->GetPosition(&posEnt);
|
|
posEnt.y = 0;
|
|
dirEnt = posEnt - m_Position;
|
|
|
|
if (DotProduct(dirEnt, m_Dir1) < 0.5)
|
|
return;
|
|
if (DotProduct(dirEnt, m_Dir2) > 0)
|
|
// Left.
|
|
m_Dir = -m_Dir2;
|
|
else
|
|
// Right.
|
|
m_Dir = m_Dir2;
|
|
m_TestTurnAngleCount = 100;
|
|
m_MoveFunction = ::TurnAndUp2;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// DetectBlocked
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::DetectBlocked()
|
|
{
|
|
if (Magnitude(m_Position-m_PosToMoveFrom) > m_DistanceBlocked)
|
|
{
|
|
m_PosToMoveFrom = m_Position;
|
|
m_TimeBlocked.Reset();
|
|
}
|
|
else if (m_TimeBlocked.Current() >= m_MaxBlockedTime)
|
|
{
|
|
m_State = timeout;
|
|
m_PosToMoveFrom = m_Position;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TurnAndUp
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::TurnAndUp()
|
|
{
|
|
// Set Old Pos.
|
|
m_OldPosition = m_Position;
|
|
if (m_State != on)
|
|
return;
|
|
|
|
// Calcul Character orientation.
|
|
m_AlignFunction(this);
|
|
|
|
// Calcul angle between character and path direction.
|
|
float angle1 = DotProduct(m_Dir1, m_Dir);
|
|
float angle2 = DotProduct(m_Dir2, m_Dir);
|
|
|
|
if (angle1 < 0.9f)
|
|
{
|
|
// Send rotate message
|
|
if (angle2 < 0.0f)
|
|
m_MessageManager->SendMessageSingle(m_Message[2], m_Character, m_Character);
|
|
else
|
|
m_MessageManager->SendMessageSingle(m_Message[3], m_Character, m_Character);
|
|
}
|
|
if (m_TestTurnAngleCount || (angle1 > m_LimitAngleCos))
|
|
// Send up message
|
|
m_MessageManager->SendMessageSingle(m_Message[0], m_Character, m_Character);
|
|
if (m_TestTurnAngleCount)
|
|
--m_TestTurnAngleCount;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TurnAndUp2
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::TurnAndUp2()
|
|
{
|
|
// Set Old Pos.
|
|
m_OldPosition = m_Position;
|
|
if (m_State != on)
|
|
return;
|
|
|
|
// Calcul Character orientation.
|
|
m_AlignFunction(this);
|
|
|
|
// Calcul angle between character and path direction.
|
|
float angle1 = DotProduct(m_Dir1, m_Dir);
|
|
float angle2 = DotProduct(m_Dir2, m_Dir);
|
|
|
|
if (angle1 < 0.99f)
|
|
{
|
|
// Send rotate message
|
|
if (angle2 < 0.0f)
|
|
m_MessageManager->SendMessageSingle(m_Message[2], m_Character, m_Character);
|
|
else
|
|
m_MessageManager->SendMessageSingle(m_Message[3], m_Character, m_Character);
|
|
}
|
|
m_MessageManager->SendMessageSingle(m_Message[0], m_Character, m_Character);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Up
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FollowProblem::Up()
|
|
{
|
|
// Set Old Pos.
|
|
m_OldPosition = m_Position;
|
|
if (m_State != on)
|
|
return;
|
|
|
|
// Calcul Character orientation.
|
|
m_AlignFunction(this);
|
|
m_MessageManager->SendMessageSingle(m_Message[0], m_Character, m_Character);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// AlignOnPath1
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void AlignOnPath1(FollowProblem *fp)
|
|
{
|
|
fp->m_Character->GetOrientation(&fp->m_Dir2, NULL, &fp->m_Dir1);
|
|
fp->m_Dir2 = -fp->m_Dir2;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// AlignOnPath2
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void AlignOnPath2(FollowProblem *fp)
|
|
{
|
|
fp->m_Character->GetOrientation(&fp->m_Dir2, NULL, &fp->m_Dir1);
|
|
fp->m_Dir1 = -fp->m_Dir1;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// AlignOnPath3
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void AlignOnPath3(FollowProblem *fp)
|
|
{
|
|
fp->m_Character->GetOrientation(NULL, &fp->m_Dir1, &fp->m_Dir2);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// AlignOnPath4
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void AlignOnPath4(FollowProblem *fp)
|
|
{
|
|
fp->m_Character->GetOrientation(NULL, &fp->m_Dir1, &fp->m_Dir2);
|
|
fp->m_Dir1 = -fp->m_Dir1;
|
|
fp->m_Dir2 = -fp->m_Dir2;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// AlignOnPath5
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void AlignOnPath5(FollowProblem *fp)
|
|
{
|
|
fp->m_Character->GetOrientation(&fp->m_Dir1, NULL, &fp->m_Dir2);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// AlignOnPath6
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void AlignOnPath6(FollowProblem *fp)
|
|
{
|
|
fp->m_Character->GetOrientation(&fp->m_Dir1, NULL, &fp->m_Dir2);
|
|
fp->m_Dir1 = -fp->m_Dir1;
|
|
fp->m_Dir2 = -fp->m_Dir2;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Up
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void ComputeDir(FollowProblem *fp)
|
|
{
|
|
fp->ComputeDir();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// EnterTele
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void EnterTele(FollowProblem *fp)
|
|
{
|
|
fp->EnterTele();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TravelTele
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void TravelTele(FollowProblem *fp)
|
|
{
|
|
fp->TravelTele();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// ExitTele
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void ExitTele(FollowProblem *fp)
|
|
{
|
|
fp->ExitTele();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TurnAndUp
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void TurnAndUp(FollowProblem *fp)
|
|
{
|
|
fp->TurnAndUp();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TurnAndUp2
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void TurnAndUp2(FollowProblem *fp)
|
|
{
|
|
fp->TurnAndUp2();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Up
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void Up(FollowProblem *fp)
|
|
{
|
|
fp->Up();
|
|
}
|