/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
//
// Grid Path Solver
//
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
#include "CKAll.h"
#include "./includes/GridManager.h"
#include "GridPathManager.h"
#define CKPGUID_HEURISTIC CKGUID(0x72604f23,0x5fe7f0f)
#define CKPGUID_PATHTYPE CKGUID(0x3e7f7035,0x7835401f)
//input
enum {INPUT_ON, INPUT_OFF};
//outpout
enum {OUTPUT_FIND, OUTPUT_NOTFIND};
//pinput
enum
{
INPUT_PARAM_TARGETPOS,
INPUT_PARAM_GOALPOS,
INPUT_PARAM_GOALREF,
INPUT_PARAM_HEURISTIC,
INPUT_PARAM_HEURISTICCOEF,
INPUT_PARAM_DIAGONAL,
INPUT_PARAM_OBSTACLELAYER,
INPUT_PARAM_THRESHOLD,
INPUT_PARAM_SLOWING,
INPUT_PARAM_LINKER,
INPUT_PARAM_LINKEROBS,
INPUT_PARAM_TIME
};
//poutpout
enum {OUTPUT_PARAM_PATH, OUTPUT_PARAM_LENGTH};
//local parameter/setting
enum
{
LOCAL_SETTING_PATHTYPE, LOCAL_SETTING_OPTIMIZE
};
CKObjectDeclaration *FillBehaviorGridPathSolverDecl();
CKERROR CreateGridPathSolverProto(CKBehaviorPrototype **);
CKERROR GridPathSolverCallback (const CKBehaviorContext& behcontext);
int GridPathSolver(const CKBehaviorContext& behcontext);
//-------------------------------------------------
// Declaration
//-------------------------------------------------
CKObjectDeclaration *FillBehaviorGridPathSolverDecl()
{
CKObjectDeclaration *od = CreateCKObjectDeclaration("Grid Path Solver");
od->SetDescription("Solve a new path finding problem.");
/* rem:
On: Activate the search.
Reset: Abord the search
Find: Is activate when the path is find.
Not Find: Is activate when the path is not find.
Target Position: Position in target referencial
Goal Position Ref: Goal referential.
Goal Position: Position in goal referencial
Heuristic Method: Method to calculate distance
Heuristic Factor: Determine importance of heuristic in calculs.
Diagonal: Enable diagonal moves.
Obstacle Layer: Layer wich stand for obstacle.
Obstacle Threshold: If obstacle layer value is higher than obstacle threshold then it is an obstacle.
Slowing Factor: Increase or decrease the value of the layer obstacle.
Use Linkers: Allow the target to use linkers
Teleporter As Obstacles: Do the target must consider teleporters as obstacles
Ms/Frame: Max time to spend for path calculation for one frame.
Path ID: Path representation
or
List of point: Path representation
or
Curve: Path representation
Path's Length: Path's Length
Path TypeChoose the representation of the path.
*/
od->SetCategory("Grids/Path Finding");
od->SetType( CKDLL_BEHAVIORPROTOTYPE);
od->SetGuid(CKGUID(0x17e75566,0xc5625a6));
od->SetAuthorGuid(VIRTOOLS_GUID);
od->SetAuthorName("Virtools");
od->SetVersion(0x00020000);
od->SetCreationFunction(CreateGridPathSolverProto);
od->SetCompatibleClassId (CKCID_3DENTITY);
return od;
}
//-------------------------------------------------
// Prototype
//-------------------------------------------------
CKERROR CreateGridPathSolverProto(CKBehaviorPrototype **pproto)
{
CKBehaviorPrototype *proto = CreateCKBehaviorPrototype("Grid Path Solver");
if(!proto) return CKERR_OUTOFMEMORY;
proto->DeclareInput("On");
proto->DeclareInput("Reset");
proto->DeclareOutput("Found");
proto->DeclareOutput("Not Found");
proto->DeclareInParameter("Position In Owner Ref", CKPGUID_VECTOR);
proto->DeclareInParameter("Goal Position", CKPGUID_VECTOR);
proto->DeclareInParameter("Goal Position Ref", CKPGUID_3DENTITY);
proto->DeclareInParameter("Heuristic Method", CKPGUID_HEURISTIC, "1");
proto->DeclareInParameter("Heuristic Factor", CKPGUID_FLOAT, "2");
proto->DeclareInParameter("Diagonal", CKPGUID_BOOL);
proto->DeclareInParameter("Obstacle Layer", CKPGUID_LAYERTYPE);
proto->DeclareInParameter("Obstacle Threshold", CKPGUID_INT);
proto->DeclareInParameter("Slowing Factor", CKPGUID_FLOAT, "1");
proto->DeclareInParameter("Use Linkers", CKPGUID_BOOL, "TRUE");
proto->DeclareInParameter("Linkers As Obstacles", CKPGUID_BOOL, "FALSE");
proto->DeclareInParameter("Ms/Frame", CKPGUID_FLOAT, "1");
proto->DeclareOutParameter("Path ID", CKPGUID_INT);
proto->DeclareOutParameter("Path's Length", CKPGUID_FLOAT);
proto->DeclareSetting("Path Type", CKPGUID_PATHTYPE, "1");
proto->DeclareSetting("Optimize Path", CKPGUID_BOOL, "TRUE");
proto->SetFlags(CK_BEHAVIORPROTOTYPE_NORMAL);
proto->SetFunction(GridPathSolver);
proto->SetBehaviorFlags((CK_BEHAVIOR_FLAGS)(CKBEHAVIOR_TARGETABLE | CKBEHAVIOR_INTERNALLYCREATEDOUTPUTPARAMS));
proto->SetBehaviorCallbackFct(GridPathSolverCallback);
*pproto = proto;
return CK_OK;
}
//-------------------------------------------------
// Fonction
//-------------------------------------------------
int GridPathSolver(const CKBehaviorContext& behcontext)
{
CKBehavior *beh = behcontext.Behavior;
GridManager *gm = (GridManager *)behcontext.Context->GetManagerByGuid(GRID_MANAGER_GUID);
GridPathManager *gridPathManager = gm->GetGridPathManager();
CK3dEntity *target;
CK3dEntity *goalRef;
VxVector targetPos;
VxVector goalPos;
int obstacleLayer;
int obstacleThreshold;
float slowingFactor;
CKBOOL linker;
CKBOOL linkerObs;
float heuristicCoef;
float timeFrame;
int state;
int heuristic;
CKBOOL diagonal;
CKBOOL optimize;
// Get the 3d entity target.
target = (CK3dEntity *)beh->GetTarget();
if (!target)
{
beh->ActivateOutput(OUTPUT_NOTFIND, TRUE);
return CKBR_OWNERERROR;
}
// ON
if(beh->IsInputActive(INPUT_ON))
{
beh->ActivateInput(INPUT_ON, FALSE);
state = gridPathManager->GetTargetStatus(target);
if (!state)
{
// Register a new path problem.
beh->GetInputParameterValue(INPUT_PARAM_TARGETPOS, &targetPos);
// In version 2 pos and ref are inversed.
if (beh->GetVersion() == 0x00020000)
{
goalRef = (CK3dEntity *)beh->GetInputParameterObject(INPUT_PARAM_GOALREF);
beh->GetInputParameterValue(INPUT_PARAM_GOALPOS, &goalPos);
}
else
{
goalRef = (CK3dEntity *)beh->GetInputParameterObject(INPUT_PARAM_GOALPOS);
beh->GetInputParameterValue(INPUT_PARAM_GOALREF, &goalPos);
}
beh->GetInputParameterValue(INPUT_PARAM_HEURISTIC, &heuristic);
beh->GetInputParameterValue(INPUT_PARAM_DIAGONAL, &diagonal);
beh->GetInputParameterValue(INPUT_PARAM_OBSTACLELAYER, &obstacleLayer);
beh->GetInputParameterValue(INPUT_PARAM_THRESHOLD, &obstacleThreshold);
beh->GetInputParameterValue(INPUT_PARAM_SLOWING, &slowingFactor);
beh->GetInputParameterValue(INPUT_PARAM_LINKER, &linker);
beh->GetInputParameterValue(INPUT_PARAM_LINKEROBS, &linkerObs);
beh->GetInputParameterValue(INPUT_PARAM_HEURISTICCOEF, &heuristicCoef);
beh->GetInputParameterValue(INPUT_PARAM_TIME, &timeFrame);
beh->GetLocalParameterValue(LOCAL_SETTING_OPTIMIZE, &optimize);
// Register the path problem...
if (!obstacleLayer || !gridPathManager->RegisterPathProblem(target, &targetPos, goalRef, &goalPos, obstacleLayer, obstacleThreshold, slowingFactor, linker, linkerObs, heuristicCoef, timeFrame, heuristic, diagonal, optimize))
{
beh->ActivateOutput(OUTPUT_NOTFIND, TRUE);
return CKBR_OWNERERROR;
}
}
return CKBR_ACTIVATENEXTFRAME;
}
if (!gridPathManager->GetNbPathProblem()) {
// Desactivate Input.
beh->ActivateInput(INPUT_OFF, FALSE);
// Activate Output.
beh->ActivateOutput(OUTPUT_NOTFIND, TRUE);
}
// OFF
if(beh->IsInputActive(INPUT_OFF))
{
beh->ActivateInput(INPUT_OFF, FALSE);
beh->ActivateOutput(OUTPUT_NOTFIND, TRUE);
gridPathManager->UnregisterPathProblem(target, FALSE);
return CKBR_OK;
}
// INTERNE
if (!(state = gridPathManager->GetTargetStatus(target)))
{
// Path Problem was not found
beh->ActivateOutput(OUTPUT_NOTFIND, TRUE);
return CKBR_OK;
}
if (state == 2)
{
// Path was found.
int pathType;
float coast;
beh->GetLocalParameterValue(LOCAL_SETTING_PATHTYPE, &pathType);
if (pathType == 1)
{
// Path ID.
int followPathID;
// Get the path and unregister the problem.
gridPathManager->GetPath(target, coast, followPathID);
gridPathManager->UnregisterPathProblem(target, TRUE);
// Send the path id to the param output.
beh->SetOutputParameterValue(OUTPUT_PARAM_PATH, &followPathID);
}
else if (pathType == 2)
{
// Array vector.
CKDataArray *dataArray = (CKDataArray *)beh->GetOutputParameterObject(OUTPUT_PARAM_PATH);
if (!dataArray)
{
dataArray = (CKDataArray *)behcontext.Context->CreateObject(CKCID_DATAARRAY, "PathArray", CK_OBJECTCREATION_DYNAMIC);
dataArray->InsertColumn(-1, CKARRAYTYPE_PARAMETER, "path node", CKPGUID_VECTOR);
behcontext.CurrentLevel->AddObject(dataArray);
}
// Get the path and unregister the problem.
gridPathManager->GetPath(target, coast, dataArray);
gridPathManager->UnregisterPathProblem(target, FALSE);
// Send the curve to the param output.
beh->SetOutputParameterObject(OUTPUT_PARAM_PATH, dataArray);
}
else if (pathType == 3)
{
// Curve.
CKCurve *curve = (CKCurve *)beh->GetOutputParameterObject(OUTPUT_PARAM_PATH);
if (!curve)
{
curve = (CKCurve *)(behcontext.Context->CreateObject(CKCID_CURVE, "Result Path", CK_OBJECTCREATION_DYNAMIC));
behcontext.CurrentLevel->AddObject(curve);
beh->SetOutputParameterObject(OUTPUT_PARAM_PATH, curve);
}
// Get the path and unregister the problem.
curve->SetColor(VxColor(255, 255, 255));
gridPathManager->GetPath(target, coast, curve);
gridPathManager->UnregisterPathProblem(target, FALSE);
// Send the curve to the param output.
beh->SetOutputParameterObject(OUTPUT_PARAM_PATH, curve);
}
// Send the coast to the param output.
coast--;
beh->SetOutputParameterValue(OUTPUT_PARAM_LENGTH, &coast);
beh->ActivateOutput(OUTPUT_FIND, TRUE);
return CKBR_OK;
}
else if (state == 3)
{
// Path was not found.
gridPathManager->UnregisterPathProblem(target, FALSE);
beh->ActivateOutput(OUTPUT_NOTFIND, TRUE);
return CKBR_OK;
}
return CKBR_ACTIVATENEXTFRAME;
}
//-------------------------------------------------
// Callback
//-------------------------------------------------
CKERROR GridPathSolverCallback (const CKBehaviorContext& behcontext)
{
CKBehavior* beh = behcontext.Behavior;
switch (behcontext.CallbackMessage)
{
case CKM_BEHAVIORSETTINGSEDITED:
{
int pathType;
CKParameterOut *pout;
beh->GetLocalParameterValue(LOCAL_SETTING_PATHTYPE, &pathType);
pout = beh->GetOutputParameter(OUTPUT_PARAM_PATH);
if (pathType == 1)
{
pout->SetGUID(CKPGUID_INT);
pout->SetName("Path ID");
}
else if (pathType == 2)
{
pout->SetGUID(CKPGUID_DATAARRAY);
pout->SetName("List of point");
}
else if (pathType == 3)
{
pout->SetGUID(CKPGUID_CURVE);
pout->SetName("Curve");
}
}
break;
}
return CKBR_OK;
}