BVB Source Codes

CRYENGINE Show MoveOp.cpp Source code

Return Download CRYENGINE: download MoveOp.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4. #include "MoveOp.h"
  5.  
  6. #include <CryAISystem/IMovementSystem.h>
  7. #include <CryAISystem/MovementRequest.h>
  8. #include "Cover/CoverSystem.h"
  9. #include "PipeUser.h"
  10. #include <CrySystem/XML/XMLAttrReader.h>
  11. #include "AIBubblesSystem/AIBubblesSystem.h"
  12. #include "Navigation/NavigationSystem/NavigationSystem.h"
  13.  
  14. MoveOpDictionaryCollection::MoveOpDictionaryCollection()
  15. {
  16.         destinationTypes.Reserve(5);
  17.         destinationTypes.Add("Target", MoveOp::Target);
  18.         destinationTypes.Add("Cover", MoveOp::Cover);
  19.         destinationTypes.Add("RefPoint", MoveOp::ReferencePoint);
  20.         destinationTypes.Add("FollowPath", MoveOp::FollowPath);
  21.         destinationTypes.Add("Formation", MoveOp::Formation);
  22. }
  23.  
  24. MoveOpDictionaryCollection g_moveOpDictionaryCollection;
  25.  
  26. MoveOp::MoveOp()
  27.         : m_movementRequestID(0)
  28.         , m_stopWithinDistanceSq(0.0f)
  29.         , m_destinationAtTimeOfMovementRequest(ZERO)
  30.         , m_destination(ReferencePoint)
  31.         , m_dangersFlags(eMNMDangers_None)
  32.         , m_requestStopWhenLeaving(false)
  33. {
  34.         m_movementStyle.SetMovingToCover(false);
  35. }
  36.  
  37. MoveOp::MoveOp(const XmlNodeRef& node)
  38.         : m_movementRequestID(0)
  39.         , m_stopWithinDistanceSq(0.0f)
  40.         , m_destinationAtTimeOfMovementRequest(ZERO)
  41.         , m_destination(ReferencePoint)
  42.         , m_dangersFlags(eMNMDangers_None)
  43.         , m_requestStopWhenLeaving(false)
  44. {
  45.         // Speed? Stance?
  46.         m_movementStyle.ReadFromXml(node);
  47.  
  48.         // Destination? Target/Cover/ReferencePoint
  49.         g_moveOpDictionaryCollection.destinationTypes.Get(node, "to", m_destination, true);
  50.         m_movementStyle.SetMovingToCover(m_destination == Cover);
  51.         m_movementStyle.SetMovingAlongDesignedPath(m_destination == FollowPath);
  52.  
  53.         if (m_destination == FollowPath)
  54.         {
  55.                 m_pathName = node->getAttr("pathName");
  56.         }
  57.  
  58.         float stopWithinDistance(0.0f);
  59.         node->getAttr("stopWithinDistance", stopWithinDistance);
  60.         SetStopWithinDistance(stopWithinDistance);
  61.  
  62.         bool shouldAvoidDangers = true;
  63.         node->getAttr("shouldAvoidDangers", shouldAvoidDangers);
  64.  
  65.         SetupDangersFlagsForDestination(shouldAvoidDangers);
  66. }
  67.  
  68. void MoveOp::SetupDangersFlagsForDestination(bool shouldAvoidDangers)
  69. {
  70.         if (!shouldAvoidDangers)
  71.         {
  72.                 m_dangersFlags = eMNMDangers_None;
  73.                 return;
  74.         }
  75.  
  76.         switch (m_destination)
  77.         {
  78.         case Target:
  79.         case Formation:
  80.                 m_dangersFlags = eMNMDangers_Explosive;
  81.                 break;
  82.         case Cover:
  83.         case ReferencePoint:
  84.                 m_dangersFlags = eMNMDangers_AttentionTarget | eMNMDangers_Explosive;
  85.                 break;
  86.         case FollowPath:
  87.                 m_dangersFlags = eMNMDangers_None;
  88.                 break;
  89.         default:
  90.                 assert(0);
  91.                 m_dangersFlags = eMNMDangers_None;
  92.                 break;
  93.         }
  94. }
  95.  
  96. void MoveOp::Enter(CPipeUser& pipeUser)
  97. {
  98.         if (m_destination != FollowPath)
  99.         {
  100.                 RequestMovementTo(DestinationPositionFor(pipeUser), pipeUser);
  101.         }
  102.         else
  103.         {
  104.                 if (m_pathName.empty())
  105.                 {
  106.                         GetClosestDesignedPath(pipeUser, m_pathName);
  107.                 }
  108.                 RequestFollowExistingPath(m_pathName.c_str(), pipeUser);
  109.         }
  110. }
  111.  
  112. void MoveOp::Leave(CPipeUser& pipeUser)
  113. {
  114.         const bool requestWasStillRunning = m_movementRequestID != 0;
  115.  
  116.         ReleaseCurrentMovementRequest();
  117.  
  118.         const bool shouldRequestStop = (m_requestStopWhenLeaving && requestWasStillRunning) || GetStatus() == eGOR_FAILED;
  119.         if (shouldRequestStop)
  120.         {
  121.                 RequestStop(pipeUser);
  122.         }
  123. }
  124.  
  125. void MoveOp::Update(CPipeUser& pipeUser)
  126. {
  127.         if (m_destination == Target || m_destination == Formation)
  128.         {
  129.                 ChaseTarget(pipeUser);
  130.         }
  131.  
  132.         const bool stopMovementWhenWithinCertainDistance = m_stopWithinDistanceSq > 0.0f;
  133.  
  134.         if (stopMovementWhenWithinCertainDistance)
  135.         {
  136.                 if (GetSquaredDistanceToDestination(pipeUser) < m_stopWithinDistanceSq)
  137.                 {
  138.                         ReleaseCurrentMovementRequest();
  139.                         RequestStop(pipeUser);
  140.                         GoalOpSucceeded();
  141.                 }
  142.         }
  143. }
  144.  
  145. void MoveOp::SetMovementStyle(MovementStyle movementStyle)
  146. {
  147.         m_movementStyle = movementStyle;
  148. }
  149.  
  150. void MoveOp::SetStopWithinDistance(float distance)
  151. {
  152.         m_stopWithinDistanceSq = square(distance);
  153. }
  154.  
  155. void MoveOp::SetRequestStopWhenLeaving(bool requestStop)
  156. {
  157.         m_requestStopWhenLeaving = requestStop;
  158. }
  159.  
  160. static CFormation* getFormation(CPipeUser& pipeUserInFormation, float range);
  161.  
  162. Vec3               MoveOp::DestinationPositionFor(CPipeUser& pipeUser)
  163. {
  164.         switch (m_destination)
  165.         {
  166.         case Target:
  167.                 {
  168.                         if (IAIObject* target = pipeUser.GetAttentionTarget())
  169.                         {
  170.                                 CPipeUser* pPipeUser = target->CastToCPipeUser();
  171.                                 const Vec3 targetPosition = pPipeUser ? pPipeUser->GetPhysicsPos() : target->GetPosInNavigationMesh(pipeUser.GetNavigationTypeID());
  172.                                 Vec3 targetVelocity = target->GetVelocity();
  173.                                 targetVelocity.z = .0f;
  174.                                 return targetPosition + targetVelocity * 0.5f;
  175.                         }
  176.                         else
  177.                         {
  178.                                 AIQueueBubbleMessage("MoveOp Destination Position",
  179.                                                      pipeUser.GetEntityID(),
  180.                                                      "I don't have a target and MoveOp is set to chase the target.",
  181.                                                      eBNS_LogWarning | eBNS_Balloon);
  182.                                 return Vec3(ZERO);
  183.                         }
  184.                 }
  185.  
  186.         case Cover:
  187.                 {
  188.                         return GetCoverRegisterLocation(pipeUser);
  189.                 }
  190.  
  191.         case ReferencePoint:
  192.                 {
  193.                         return pipeUser.GetRefPoint()->GetPos();
  194.                 }
  195.  
  196.         case Formation:
  197.                 {
  198.                         if (IAIObject* pIAIObject = pipeUser.GetSpecialAIObject("formation", 100000.0f)) // 2013-11-08 [christianw]: the formation leader can now be up to 100 km (!) away before the followers give up (was implicitly 20 meters before, c. f. "range" parameter for CPipeUser::GetSpecialAIObject())
  199.                         {
  200.                                 m_formationInfo.positionInFormation = pIAIObject->GetPos();
  201.  
  202.                                 if (CFormation* formation = getFormation(pipeUser, 100000.0f))
  203.                                 {
  204.                                         if (const CPathMarker* pm = formation->GetPathMarker())
  205.                                         {
  206.                                                 int pointIndex = formation->GetPointIndex(GetWeakRef(&pipeUser));
  207.                                                 if (pointIndex != -1)
  208.                                                 {
  209.                                                         // get offset in formation
  210.                                                         // get direction in path marker at offset.y (the follow distance)
  211.                                                         Vec3 offset;
  212.                                                         formation->GetPointOffset(pointIndex, offset);
  213.                                                         const Vec3 dir = pm->GetDirectionAtDistanceFromNewestPoint(offset.y);
  214.                                                         const float lookAheadDistance = 6.0f; // experimental value
  215.                                                         const Vec3 positionToMoveTo = m_formationInfo.positionInFormation + dir * lookAheadDistance;
  216.  
  217.                                                         if (gAIEnv.pNavigationSystem->IsPointReachableFromPosition(pipeUser.GetNavigationTypeID(), pipeUser.GetPathAgentEntity(), pipeUser.GetEntity()->GetPos(), positionToMoveTo))
  218.                                                         {
  219.                                                                 m_formationInfo.positionInFormationIsReachable = true;
  220.                                                                 return positionToMoveTo;
  221.                                                         }
  222.                                                         else
  223.                                                         {
  224.                                                                 m_formationInfo.positionInFormationIsReachable = false;
  225.  
  226.                                                                 // follow the leader slowly until our formation slot is reachable again
  227.                                                                 if (pm->GetPointCount() > 0)
  228.                                                                 {
  229.                                                                         const float distanceBehindLeader = 1.0f;  // experimental value
  230.                                                                         return pm->GetPointAtDistanceFromNewestPoint(distanceBehindLeader);
  231.                                                                 }
  232.                                                         }
  233.                                                 }
  234.                                         }
  235.                                 }
  236.                                 // fallback
  237.                                 const Vec3 targetVelocity = pipeUser.GetFormationVelocity();
  238.                                 const float lookAheadDistanceRelativeToTargetVelocity = 0.5f;
  239.                                 return m_formationInfo.positionInFormation + targetVelocity * lookAheadDistanceRelativeToTargetVelocity;
  240.                         }
  241.                         else
  242.                         {
  243.                                 AIQueueBubbleMessage("MoveOp seeking formation failed",
  244.                                                      pipeUser.GetEntityID(),
  245.                                                      "I don't have a formation and MoveOp is set to chase it.",
  246.                                                      eBNS_LogWarning | eBNS_Balloon);
  247.                                 return Vec3(ZERO);
  248.                         }
  249.                 }
  250.  
  251.         default:
  252.                 {
  253.                         assert(0);
  254.                         return Vec3Constants<float>::fVec3_Zero;
  255.                 }
  256.         }
  257. }
  258.  
  259. Vec3 MoveOp::GetCoverRegisterLocation(const CPipeUser& pipeUser) const
  260. {
  261.         if (CoverID coverID = pipeUser.GetCoverRegister())
  262.         {
  263.                 const float distanceToCover = pipeUser.GetParameters().distanceToCover;
  264.                 return gAIEnv.pCoverSystem->GetCoverLocation(coverID, distanceToCover);
  265.         }
  266.         else
  267.         {
  268.                 assert(0);
  269.                 AIQueueBubbleMessage("MoveOp:CoverLocation", pipeUser.GetEntityID(), "MoveOp failed to get the cover location due to an invalid Cover ID in the cover register.", eBNS_LogWarning | eBNS_Balloon | eBNS_BlockingPopup);
  270.                 return Vec3Constants<float>::fVec3_Zero;
  271.         }
  272. }
  273.  
  274. void MoveOp::RequestMovementTo(const Vec3& position, CPipeUser& pipeUser)
  275. {
  276.         assert(!m_movementRequestID);
  277.  
  278.         MovementRequest movementRequest;
  279.         movementRequest.entityID = pipeUser.GetEntityID();
  280.         movementRequest.destination = position;
  281.         movementRequest.callback = functor(*this, &MoveOp::MovementRequestCallback);
  282.         movementRequest.style = m_movementStyle;
  283.         movementRequest.dangersFlags = m_dangersFlags;
  284.  
  285.         m_movementRequestID = gEnv->pAISystem->GetMovementSystem()->QueueRequest(movementRequest);
  286.  
  287.         m_destinationAtTimeOfMovementRequest = position;
  288. }
  289.  
  290. void MoveOp::RequestFollowExistingPath(const char* pathName, CPipeUser& pipeUser)
  291. {
  292.         assert(pathName);
  293.  
  294.         if (!pathName)
  295.                 return;
  296.  
  297.         CAIActor* pCAIActor = pipeUser.CastToCAIActor();
  298.         assert(pCAIActor);
  299.         if (!pCAIActor)
  300.                 return;
  301.  
  302.         pCAIActor->SetPathToFollow(pathName);
  303.  
  304.         MovementRequest movementRequest;
  305.         movementRequest.entityID = pipeUser.GetEntityID();
  306.         movementRequest.callback = functor(*this, &MoveOp::MovementRequestCallback);
  307.         movementRequest.style = m_movementStyle;
  308.  
  309.         m_movementRequestID = gEnv->pAISystem->GetMovementSystem()->QueueRequest(movementRequest);
  310.  
  311. }
  312.  
  313. void MoveOp::ReleaseCurrentMovementRequest()
  314. {
  315.         if (m_movementRequestID)
  316.         {
  317.                 gEnv->pAISystem->GetMovementSystem()->CancelRequest(m_movementRequestID);
  318.                 m_movementRequestID = 0;
  319.         }
  320. }
  321.  
  322. void MoveOp::MovementRequestCallback(const MovementRequestResult& result)
  323. {
  324.         assert(m_movementRequestID == result.requestID);
  325.  
  326.         m_movementRequestID = 0;
  327.  
  328.         if (result == MovementRequestResult::ReachedDestination)
  329.         {
  330.                 GoalOpSucceeded();
  331.         }
  332.         else
  333.         {
  334.                 GoalOpFailed();
  335.  
  336.                 if (m_destination == Cover)
  337.                 {
  338.                         // Todo: Blacklist cover
  339.                 }
  340.         }
  341. }
  342.  
  343. static CFormation* getFormation(CPipeUser& pipeUserInFormation, float range)
  344. {
  345.         CAISystem* pAISystem = GetAISystem();
  346.         CFormation* pFormation = NULL;  // return value
  347.  
  348.         if (CLeader* pLeader = pAISystem->GetLeader(pipeUserInFormation.GetGroupId()))
  349.         {
  350.                 if (CAIObject* pFormationOwner = pLeader->GetFormationOwner().GetAIObject())
  351.                 {
  352.                         pFormation = pFormationOwner->m_pFormation;
  353.                 }
  354.         }
  355.  
  356.         if (!pFormation)
  357.         {
  358.                 IAIObject* pBoss = pAISystem->GetNearestObjectOfTypeInRange(&pipeUserInFormation, AIOBJECT_ACTOR, 0, range, AIFAF_HAS_FORMATION | AIFAF_INCLUDE_DEVALUED | AIFAF_SAME_GROUP_ID);
  359.                 if (!pBoss)
  360.                         pBoss = pAISystem->GetNearestObjectOfTypeInRange(&pipeUserInFormation, AIOBJECT_VEHICLE, 0, range, AIFAF_HAS_FORMATION | AIFAF_INCLUDE_DEVALUED | AIFAF_SAME_GROUP_ID);
  361.  
  362.                 if (CAIObject* pTheBoss = static_cast<CAIObject*>(pBoss))
  363.                 {
  364.                         pFormation = pTheBoss->m_pFormation;
  365.                 }
  366.         }
  367.  
  368.         return pFormation;
  369. }
  370.  
  371. void MoveOp::ChaseTarget(CPipeUser& pipeUser)
  372. {
  373.         const Vec3 targetPosition = DestinationPositionFor(pipeUser);
  374.  
  375.         const float targetDeviation = targetPosition.GetSquaredDistance(m_destinationAtTimeOfMovementRequest);
  376.         const float deviationThreshold = square(0.5f);
  377.  
  378.         if (targetDeviation > deviationThreshold)
  379.         {
  380.                 ReleaseCurrentMovementRequest();
  381.                 RequestMovementTo(targetPosition, pipeUser);
  382.         }
  383.  
  384.         if (m_destination == Formation)
  385.         {
  386.                 if (CFormation* formation = getFormation(pipeUser, 100000.0f))
  387.                 {
  388.                         if (CAIObject* formationOwner = formation->GetOwner())
  389.                         {
  390.                                 if (CAIActor* formationOwnerAsAIActor = formationOwner->CastToCAIActor())
  391.                                 {
  392.                                         if (formation->GetPathMarker())
  393.                                         {
  394.                                                 float newSpeed = formationOwnerAsAIActor->GetState().fMovementUrgency;
  395.  
  396.                                                 if (m_formationInfo.positionInFormationIsReachable)
  397.                                                 {
  398.                                                         // check for whether we have to catch up with the formation owner, slow down or whether it's ok to move along with the same speed as he does
  399.  
  400.                                                         static const float innerRadiusSqr = square(2.0f); // experimental value
  401.                                                         static const float outerRadiusSqr = square(4.0f); // experimental value
  402.  
  403.                                                         const float distanceToFormationSlotSqr = (pipeUser.GetPos() - m_formationInfo.positionInFormation).GetLengthSquared();
  404.  
  405.                                                         const Vec3 futureFormationSlot = formation->GetPathMarker()->GetPointAtDistance(m_formationInfo.positionInFormation, 2.0f);
  406.                                                         const Vec3 dirSelfToFormationSlot = (m_formationInfo.positionInFormation - pipeUser.GetPos()).GetNormalized();
  407.                                                         const Vec3 dirFormationSlotToFutureFormationSlot = (futureFormationSlot - m_formationInfo.positionInFormation).GetNormalized();
  408.                                                         const float dot = dirSelfToFormationSlot * dirFormationSlotToFutureFormationSlot;
  409.  
  410.                                                         // check for state transition
  411.                                                         switch (m_formationInfo.state)
  412.                                                         {
  413.                                                         case FormationInfo::State_MatchingLeaderSpeed:
  414.                                                                 if (distanceToFormationSlotSqr > outerRadiusSqr)
  415.                                                                 {
  416.                                                                         if (dot > 0.0f)
  417.                                                                                 m_formationInfo.state = FormationInfo::State_CatchingUp;
  418.                                                                         else
  419.                                                                                 m_formationInfo.state = FormationInfo::State_SlowingDown;
  420.                                                                 }
  421.                                                                 else if (distanceToFormationSlotSqr > innerRadiusSqr)
  422.                                                                 {
  423.                                                                         if (dot < 0.0f)  // we're ahead -> prevent slowly outrunning our nav-mesh path
  424.                                                                                 m_formationInfo.state = FormationInfo::State_SlowingDown;
  425.                                                                 }
  426.                                                                 break;
  427.  
  428.                                                         case FormationInfo::State_CatchingUp:
  429.                                                                 if (distanceToFormationSlotSqr < innerRadiusSqr)
  430.                                                                 {
  431.                                                                         m_formationInfo.state = FormationInfo::State_MatchingLeaderSpeed;
  432.                                                                 }
  433.                                                                 else if (dot < 0.0f) // sudden change in direction occurred
  434.                                                                 {
  435.                                                                         m_formationInfo.state = FormationInfo::State_MatchingLeaderSpeed;
  436.                                                                 }
  437.                                                                 break;
  438.  
  439.                                                         case FormationInfo::State_SlowingDown:
  440.                                                                 if (distanceToFormationSlotSqr < innerRadiusSqr)
  441.                                                                 {
  442.                                                                         if (dot > 0.0f)  // we're behind
  443.                                                                                 m_formationInfo.state = FormationInfo::State_MatchingLeaderSpeed;
  444.                                                                 }
  445.                                                                 else if (dot > 0.0f) // sudden change in direction occurred
  446.                                                                 {
  447.                                                                         m_formationInfo.state = FormationInfo::State_MatchingLeaderSpeed;
  448.                                                                 }
  449.                                                                 break;
  450.                                                         }
  451.  
  452.                                                         switch (m_formationInfo.state)
  453.                                                         {
  454.                                                         case FormationInfo::State_MatchingLeaderSpeed:
  455.                                                                 // nothing, just adhere to the leader's speed
  456.                                                                 break;
  457.  
  458.                                                         case FormationInfo::State_CatchingUp:
  459.                                                                 newSpeed = std::max(1.0f, newSpeed * 1.5f); // experimental values
  460.                                                                 break;
  461.  
  462.                                                         case FormationInfo::State_SlowingDown:
  463.                                                                 newSpeed = std::min(0.3f, newSpeed * 0.5f); // experimental values
  464.                                                                 break;
  465.                                                         }
  466.                                                 }
  467.                                                 else
  468.                                                 {
  469.                                                         // our formation slot is not reachable, and we're moving behind the leader already, so keep a slightly slower speed than the leader
  470.                                                         const float fractionOfLeaderSpeed = 0.8f; // experimental value
  471.                                                         newSpeed *= fractionOfLeaderSpeed;
  472.                                                 }
  473.  
  474.                                                 pipeUser.SetSpeed(newSpeed);
  475.                                                 m_movementStyle.SetSpeedLiteral(newSpeed);    // also use the changed speed when re-pathing
  476.                                         }
  477.                                 }
  478.                         }
  479.                 }
  480.         }
  481. }
  482.  
  483. float MoveOp::GetSquaredDistanceToDestination(CPipeUser& pipeUser)
  484. {
  485.         const Vec3 destinationPosition = DestinationPositionFor(pipeUser);
  486.         return destinationPosition.GetSquaredDistance(pipeUser.GetPos());
  487. }
  488.  
  489. void MoveOp::RequestStop(CPipeUser& pipeUser)
  490. {
  491.         MovementRequest movementRequest;
  492.         movementRequest.entityID = pipeUser.GetEntityID();
  493.         movementRequest.type = MovementRequest::Stop;
  494.         gEnv->pAISystem->GetMovementSystem()->QueueRequest(movementRequest);
  495. }
  496.  
  497. void MoveOp::GetClosestDesignedPath(CPipeUser& pipeUser, stack_string& closestPathName)
  498. {
  499.         const Vec3& userPosition = pipeUser.GetPos();
  500.         const ShapeMap& shapesMap = gAIEnv.pNavigation->GetDesignerPaths();
  501.         ShapeMap::const_iterator currentShapeIt = shapesMap.begin();
  502.         ShapeMap::const_iterator endShapesMap = shapesMap.end();
  503.         float minDistance = FLT_MAX;
  504.         for (; currentShapeIt != endShapesMap; ++currentShapeIt)
  505.         {
  506.                 float distanceToNearestPointOnPath;
  507.                 Vec3 closestPoint;
  508.                 currentShapeIt->second.NearestPointOnPath(userPosition, false, distanceToNearestPointOnPath, closestPoint);
  509.                 if (distanceToNearestPointOnPath < minDistance)
  510.                 {
  511.                         minDistance = distanceToNearestPointOnPath;
  512.                         closestPathName = currentShapeIt->first;
  513.                 }
  514.         }
  515. }
  516.  
downloadMoveOp.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top