BVB Source Codes

CRYENGINE Show OwnerLinearInterpolatorNode.cpp Source code

Return Download CRYENGINE: download OwnerLinearInterpolatorNode.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.  
  5. #include <CryFlowGraph/IFlowBaseNode.h>
  6.  
  7. class CMoveEntityTo : public CFlowBaseNode<eNCT_Instanced>
  8. {
  9.         enum EInPorts
  10.         {
  11.                 IN_DEST = 0,
  12.                 IN_DYN_DEST,
  13.                 IN_VALUETYPE,
  14.                 IN_VALUE,
  15.                 IN_EASEIN,
  16.                 IN_EASEOUT,
  17.                 IN_COORDSYS,
  18.                 IN_START,
  19.                 IN_STOP
  20.         };
  21.  
  22.         enum EValueType
  23.         {
  24.                 VT_SPEED = 0,
  25.                 VT_TIME
  26.         };
  27.         enum ECoordSys
  28.         {
  29.                 CS_PARENT = 0,
  30.                 CS_WORLD,
  31.                 CS_LOCAL
  32.         };
  33.         enum EOutPorts
  34.         {
  35.                 OUT_CURRENT = 0,
  36.                 OUT_START,
  37.                 OUT_STOP,
  38.                 OUT_FINISH,
  39.                 OUT_DONE
  40.         };
  41.  
  42.         Vec3       m_position;
  43.         Vec3       m_destination;
  44.         Vec3       m_startPos; // position the entity had when Start was last triggered
  45.         float      m_lastFrameTime;
  46.         float      m_topSpeed;
  47.         float      m_easeOutDistance;
  48.         float      m_easeInDistance;
  49.         float      m_startTime;
  50.         ECoordSys  m_coorSys;
  51.         EValueType m_valueType;
  52.         bool       m_bActive;
  53.         bool       m_stopping; // this is used as a workaround for a physics problem: when the velocity is set to 0, the object still can move, for 1 more frame, with the previous velocity.
  54.         // calling Action() with threadSafe=1 does not solve that.
  55.         // TODO: im not sure about the whole "stopping" thing. why just 1 frame? it probably could be even more than 1 in some situations, or 0. not changing it now, but keep an eye on it.
  56.         bool               m_bForceFinishAsTooNear; // force finish when the target is too near. This avoids a problem with rapidly moving target position that is updated on every frame, when a fixed time is specified for the movement
  57.         bool               m_bUsePhysicUpdate;
  58.         static const float EASE_MARGIN_FACTOR;
  59.  
  60. public:
  61.         CMoveEntityTo(SActivationInfo* pActInfo)
  62.                 : m_position(ZERO),
  63.                 m_destination(ZERO),
  64.                 m_startPos(ZERO),
  65.                 m_lastFrameTime(0.0f),
  66.                 m_topSpeed(0.0f),
  67.                 m_easeOutDistance(0.0f),
  68.                 m_easeInDistance(0.0f),
  69.                 m_coorSys(CS_WORLD),
  70.                 m_valueType(VT_SPEED),
  71.                 m_startTime(0.f),
  72.                 m_bActive(false),
  73.                 m_stopping(false),
  74.                 m_bForceFinishAsTooNear(false),
  75.                 m_bUsePhysicUpdate(false)
  76.         {
  77.         }
  78.  
  79.         IFlowNodePtr Clone(SActivationInfo* pActInfo)
  80.         {
  81.                 return new CMoveEntityTo(pActInfo);
  82.         }
  83.  
  84.         virtual void Serialize(SActivationInfo* pActInfo, TSerialize ser)
  85.         {
  86.                 ser.BeginGroup("Local");
  87.                 ser.Value("Active", m_bActive);
  88.                 if (m_bActive)
  89.                 {
  90.                         ser.Value("position", m_position);
  91.                         ser.Value("destination", m_destination);
  92.                         ser.Value("startPos", m_startPos);
  93.                         ser.Value("lastFrameTime", m_lastFrameTime);
  94.                         ser.Value("topSpeed", m_topSpeed);
  95.                         ser.Value("easeInDistance", m_easeInDistance);
  96.                         ser.Value("easeOutDistance", m_easeOutDistance);
  97.                         ser.Value("stopping", m_stopping);
  98.                         ser.Value("startTime", m_startTime);
  99.                         ser.Value("bForceFinishAsTooNear", m_bForceFinishAsTooNear);
  100.                 }
  101.                 ser.EndGroup();
  102.  
  103.                 if (ser.IsReading())
  104.                 {
  105.                         m_coorSys = (ECoordSys)GetPortInt(pActInfo, IN_COORDSYS);
  106.                         m_valueType = (EValueType)GetPortInt(pActInfo, IN_VALUETYPE);
  107.                 }
  108.         }
  109.  
  110.         virtual void GetConfiguration(SFlowNodeConfig& config)
  111.         {
  112.                 static const SInputPortConfig in_config[] =
  113.                 {
  114.                         InputPortConfig<Vec3>("Destination",      _HELP("Destination")),
  115.                         InputPortConfig<bool>("DynamicUpdate",    true,                                             _HELP("If dynamic update of Destination [follow-during-movement] is allowed or not"),                                  _HELP("DynamicUpdate")),
  116.                         InputPortConfig<int>("ValueType",         0,                                                _HELP("Defines if the 'Value' input will be interpreted as speed or as time (duration)."),                             _HELP("ValueType"),      _UICONFIG("enum_int:speed=0,time=1")),
  117.                         InputPortConfig<float>("Speed",           0.f,                                              _HELP("Speed (m/sec) or time (duration in secs), depending on 'ValueType' input."),                                    _HELP("Value")),
  118.                         InputPortConfig<float>("EaseDistance",    0.f,                                              _HELP("Distance from destination at which the moving entity starts slowing down (0=no slowing down)"),                 _HELP("EaseInDistance")),
  119.                         InputPortConfig<float>("EaseOutDistance", 0.f,                                              _HELP("Distance from destination at which the moving entity starts slowing down (0=no slowing down)")),
  120.                         InputPortConfig<int>("CoordSys",          0,                                                _HELP("Destination in world, local or parent space (warning : parent space doesn't work if your parent is a brush)"),  _HELP("CoordSys"),       _UICONFIG("enum_int:Parent=0,World=1,Local=2")),
  121.                         InputPortConfig_Void("Start",             _HELP("Trigger this port to start the movement")),
  122.                         InputPortConfig_Void("Stop",              _HELP("Trigger this port to stop the movement")),
  123.                         { 0 }
  124.                 };
  125.                 static const SOutputPortConfig out_config[] =
  126.                 {
  127.                         OutputPortConfig<Vec3>("Current",    _HELP("Current position")),
  128.                         OutputPortConfig_Void("Start",       _HELP("Triggered when start input is triggered")),
  129.                         OutputPortConfig_Void("Stop",        _HELP("Triggered when stop input is triggered")),
  130.                         OutputPortConfig_Void("Finish",      _HELP("Triggered when destination is reached")),
  131.                         OutputPortConfig_Void("DoneTrigger", _HELP("Triggered when destination is reached or stop input is triggered"),_HELP("Done")),
  132.                         { 0 }
  133.                 };
  134.                 config.sDescription = _HELP("Move an entity to a destination position at a defined speed or in a defined interval of time");
  135.                 config.nFlags |= EFLN_TARGET_ENTITY | EFLN_AISEQUENCE_SUPPORTED;
  136.                 config.pInputPorts = in_config;
  137.                 config.pOutputPorts = out_config;
  138.                 config.SetCategory(EFLN_APPROVED);
  139.         }
  140.  
  141.         //////////////////////////////////////////////////////////////////////////
  142.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  143.         {
  144.                 switch (event)
  145.                 {
  146.                 case eFE_Activate:
  147.                         {
  148.                                 OnActivate(pActInfo);
  149.                                 break;
  150.                         }
  151.                 case eFE_Initialize:
  152.                         {
  153.                                 OnInitialize(pActInfo);
  154.                                 break;
  155.                         }
  156.  
  157.                 case eFE_Update:
  158.                         {
  159.                                 OnUpdate(pActInfo);
  160.                                 break;
  161.                         }
  162.                 }
  163.                 ;
  164.         };
  165.  
  166.         //////////////////////////////////////////////////////////////////////////
  167.         void OnActivate(SActivationInfo* pActInfo)
  168.         {
  169.                 // update destination only if dynamic update is enabled. otherwise destination is read on Start/Reset only
  170.                 if (m_bActive && IsPortActive(pActInfo, IN_DEST) && GetPortBool(pActInfo, IN_DYN_DEST) == true)
  171.                 {
  172.                         ReadDestinationPosFromInput(pActInfo);
  173.                         if (m_valueType == VT_TIME)
  174.                                 CalcSpeedFromTimeInput(pActInfo);
  175.                 }
  176.                 if (m_bActive && IsPortActive(pActInfo, IN_VALUE))
  177.                 {
  178.                         ReadSpeedFromInput(pActInfo);
  179.                 }
  180.                 if (IsPortActive(pActInfo, IN_START))
  181.                 {
  182.                         Start(pActInfo);
  183.                 }
  184.                 if (IsPortActive(pActInfo, IN_STOP))
  185.                 {
  186.                         Stop(pActInfo);
  187.                 }
  188.  
  189.                 // we dont support dynamic change of those inputs
  190.                 assert(!IsPortActive(pActInfo, IN_COORDSYS));
  191.                 assert(!IsPortActive(pActInfo, IN_VALUETYPE));
  192.         }
  193.  
  194.         //////////////////////////////////////////////////////////////////////////
  195.         void OnInitialize(SActivationInfo* pActInfo)
  196.         {
  197.                 m_bActive = false;
  198.                 m_position = ZERO;
  199.                 m_coorSys = (ECoordSys)GetPortInt(pActInfo, IN_COORDSYS);
  200.                 m_valueType = (EValueType)GetPortInt(pActInfo, IN_VALUETYPE);
  201.                 IEntity* pEnt = pActInfo->pEntity;
  202.                 if (pEnt)
  203.                         m_position = pEnt->GetWorldPos();
  204.                 ActivateOutput(pActInfo, OUT_CURRENT, m_position);  // i dont see a sense for this, but lets keep it for now
  205.                 pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  206.         }
  207.  
  208.         //////////////////////////////////////////////////////////////////////////
  209.         void OnUpdate(SActivationInfo* pActInfo)
  210.         {
  211.                 IEntity* pEnt = pActInfo->pEntity;
  212.                 if (!pEnt)
  213.                 {
  214.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  215.                         return;
  216.                 }
  217.                 IPhysicalEntity* pPhysEnt = m_bUsePhysicUpdate ? pEnt->GetPhysics() : NULL;
  218.  
  219.                 if (m_stopping)
  220.                 {
  221.                         m_stopping = false;
  222.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  223.  
  224.                         if (pPhysEnt == NULL)
  225.                         {
  226.                                 SetPos(pActInfo, m_destination);
  227.                         }
  228.  
  229.                         m_bActive = false;
  230.                         return;
  231.                 }
  232.  
  233.                 if (!m_bActive)
  234.                 {
  235.                         return;
  236.                 }
  237.                 float time = gEnv->pTimer->GetFrameStartTime().GetSeconds();
  238.                 float timeDifference = time - m_lastFrameTime;
  239.                 m_lastFrameTime = time;
  240.  
  241.                 // note - if there's no physics then this will be the same, but if the platform is moved through physics, then
  242.                 //        we have to get back the actual movement - this maybe framerate dependent.
  243.                 m_position = pActInfo->pEntity->GetWorldPos();
  244.  
  245.                 // let's compute the movement vector now
  246.                 Vec3 oldPosition = m_position;
  247.  
  248.                 const float valuesMagnitude = m_destination.GetLength();
  249.                 const float movementEpsilon = valuesMagnitude * 0.000001f; // use an epsilon with a size relevant to the magnitude of distances we handle
  250.                 if (m_bForceFinishAsTooNear || m_position.IsEquivalent(m_destination, movementEpsilon))
  251.                 {
  252.                         m_position = m_destination;
  253.                         oldPosition = m_destination;
  254.                         ActivateOutput(pActInfo, OUT_DONE, true);
  255.                         ActivateOutput(pActInfo, OUT_FINISH, true);
  256.                         SetPos(pActInfo, m_position); // for finishing we have to make a manual setpos even if there is physics involved, to make sure the entity will be where it should.
  257.                         if (pPhysEnt)
  258.                         {
  259.                                 pe_action_set_velocity setVel;
  260.                                 setVel.v = ZERO;
  261.                                 pPhysEnt->Action(&setVel);
  262.  
  263.                                 m_stopping = true;
  264.                         }
  265.                         else
  266.                         {
  267.                                 pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  268.                                 m_bActive = false;
  269.                         }
  270.                 }
  271.                 else
  272.                 {
  273.                         Vec3 direction = m_destination - m_position;
  274.                         float distance = direction.GetLength();
  275.                         Vec3 directionAndSpeed = direction.normalized();
  276.  
  277.                         // ease-area calcs
  278.                         float distanceForEaseOutCalc = distance + m_easeOutDistance * EASE_MARGIN_FACTOR;
  279.                         if (distanceForEaseOutCalc < m_easeOutDistance) // takes care of m_easeOutDistance being 0
  280.                         {
  281.                                 directionAndSpeed *= distanceForEaseOutCalc / m_easeOutDistance;
  282.                         }
  283.                         else  // init code makes sure both eases dont overlap, when the movement is time defined. when it is speed defined, only ease out is applied if they overlap.
  284.                         {
  285.                                 if (m_easeInDistance > 0.f)
  286.                                 {
  287.                                         Vec3 vectorFromStart = m_position - m_startPos;
  288.                                         float distanceFromStart = vectorFromStart.GetLength();
  289.                                         float distanceForEaseInCalc = distanceFromStart + m_easeInDistance * EASE_MARGIN_FACTOR;
  290.                                         if (distanceForEaseInCalc < m_easeInDistance)
  291.                                         {
  292.                                                 directionAndSpeed *= distanceForEaseInCalc / m_easeInDistance;
  293.                                         }
  294.                                 }
  295.                         }
  296.  
  297.                         directionAndSpeed *= (m_topSpeed * timeDifference);
  298.  
  299.                         if (direction.GetLength() < directionAndSpeed.GetLength())
  300.                         {
  301.                                 m_position = m_destination;
  302.                                 m_bForceFinishAsTooNear = true;
  303.                         }
  304.                         else
  305.                                 m_position += directionAndSpeed;
  306.                 }
  307.                 ActivateOutput(pActInfo, OUT_CURRENT, m_position);
  308.                 if (pPhysEnt == NULL)
  309.                 {
  310.                         SetPos(pActInfo, m_position);
  311.                 }
  312.                 else
  313.                 {
  314.                         pe_action_set_velocity setVel;
  315.                         float rTimeStep = timeDifference > 0.000001f ? 1.f / timeDifference : 0.0f;
  316.                         setVel.v = (m_position - oldPosition) * rTimeStep;
  317.                         pPhysEnt->Action(&setVel);
  318.                 }
  319.         }
  320.  
  321.         //////////////////////////////////////////////////////////////////////////
  322.         bool CanUsePhysicsUpdate(IEntity* pEntity)
  323.         {
  324.                 // Do not use physics when
  325.                 // a) there is no physics geometry
  326.                 // b) the entity is a child
  327.                 // c) the entity is not rigid
  328.  
  329.                 if (IStatObj* pStatObj = pEntity->GetStatObj(ENTITY_SLOT_ACTUAL))
  330.                 {
  331.                         phys_geometry* pPhysGeom = pStatObj->GetPhysGeom();
  332.                         if (!pPhysGeom)
  333.                         {
  334.                                 return false;
  335.                         }
  336.                 }
  337.                 IPhysicalEntity* pPhysEnt = pEntity->GetPhysics();
  338.  
  339.                 if (!pPhysEnt)
  340.                 {
  341.                         return false;
  342.                 }
  343.                 else
  344.                 {
  345.                         if (pEntity->GetParent() || pPhysEnt->GetType() == PE_STATIC)
  346.                         {
  347.                                 return false;
  348.                         }
  349.                 }
  350.                 return true;
  351.         }
  352.  
  353.         //////////////////////////////////////////////////////////////////////////
  354.         void SetPos(SActivationInfo* pActInfo, const Vec3& vPos)
  355.         {
  356.                 if (pActInfo->pEntity)
  357.                 {
  358.                         if (pActInfo->pEntity->GetParent())
  359.                         {
  360.                                 Matrix34 tm = pActInfo->pEntity->GetWorldTM();
  361.                                 tm.SetTranslation(vPos);
  362.                                 pActInfo->pEntity->SetWorldTM(tm);
  363.                         }
  364.                         else
  365.                                 pActInfo->pEntity->SetPos(vPos);
  366.                 }
  367.         }
  368.  
  369.         //////////////////////////////////////////////////////////////////////////
  370.         void ReadDestinationPosFromInput(SActivationInfo* pActInfo)
  371.         {
  372.                 m_destination = GetPortVec3(pActInfo, IN_DEST);
  373.                 if (pActInfo->pEntity)
  374.                 {
  375.                         switch (m_coorSys)
  376.                         {
  377.                         case CS_PARENT:
  378.                                 {
  379.                                         IEntity* pParent = pActInfo->pEntity->GetParent();
  380.                                         if (pParent)
  381.                                         {
  382.                                                 const Matrix34& mat = pParent->GetWorldTM();
  383.                                                 m_destination = mat.TransformPoint(m_destination);
  384.                                         }
  385.                                 }
  386.                                 break;
  387.                         case CS_LOCAL:
  388.                                 {
  389.                                         const Matrix34& mat = pActInfo->pEntity->GetWorldTM();
  390.                                         m_destination = mat.TransformPoint(m_destination);
  391.                                 }
  392.                                 break;
  393.                         case CS_WORLD:
  394.                         default:
  395.                                 break;
  396.                         }
  397.                 }
  398.         }
  399.  
  400.         //////////////////////////////////////////////////////////////////////////
  401.         void ReadSpeedFromInput(SActivationInfo* pActInfo)
  402.         {
  403.                 if (m_valueType == VT_TIME)
  404.                 {
  405.                         CalcSpeedFromTimeInput(pActInfo);
  406.                 }
  407.                 else
  408.                 {
  409.                         m_topSpeed = GetPortFloat(pActInfo, IN_VALUE);
  410.                         if (m_topSpeed < 0.0f) m_topSpeed = 0.0f;
  411.                 }
  412.         }
  413.  
  414.         //////////////////////////////////////////////////////////////////////////
  415.         // when the inputs are set to work with "time" instead of speed, we just calculate speed from that time value
  416.         void CalcSpeedFromTimeInput(SActivationInfo* pActInfo)
  417.         {
  418.                 assert(GetPortInt(pActInfo, IN_VALUETYPE) == VT_TIME);
  419.                 float movementDuration = GetPortFloat(pActInfo, IN_VALUE);
  420.                 float timePassed = gEnv->pTimer->GetFrameStartTime().GetSeconds() - m_startTime;
  421.                 float movementDurationLeft = movementDuration - timePassed;
  422.                 if (movementDurationLeft < 0.0001f) movementDurationLeft = 0.0001f;
  423.                 Vec3 movement = m_destination - m_position;
  424.                 float distance = movement.len();
  425.  
  426.                 if (m_easeInDistance + m_easeOutDistance > distance)    // make sure they dont overlap
  427.                         m_easeInDistance = distance - m_easeOutDistance;
  428.                 float distanceNoEase = distance - (m_easeInDistance + m_easeOutDistance);
  429.  
  430.                 const float factorAverageSpeedEase = 0.5f; // not real because is not lineal, but is good enough for this
  431.                 float realEaseInDistance = max(m_easeInDistance - m_easeInDistance * EASE_MARGIN_FACTOR, 0.f);
  432.                 float realEaseOutDistance = max(m_easeOutDistance - m_easeOutDistance * EASE_MARGIN_FACTOR, 0.f);
  433.  
  434.                 m_topSpeed = ((realEaseInDistance / factorAverageSpeedEase) + distanceNoEase + (realEaseOutDistance / factorAverageSpeedEase)) / movementDurationLeft;          // this comes just from V = S / T;
  435.         }
  436.  
  437.         //////////////////////////////////////////////////////////////////////////
  438.         void Start(SActivationInfo* pActInfo)
  439.         {
  440.                 IEntity* pEnt = pActInfo->pEntity;
  441.                 if (!pEnt)
  442.                         return;
  443.  
  444.                 m_bForceFinishAsTooNear = false;
  445.                 m_position = m_coorSys == CS_WORLD ? pEnt->GetWorldPos() : pEnt->GetPos();
  446.                 m_startPos = m_position;
  447.                 m_lastFrameTime = gEnv->pTimer->GetFrameStartTime().GetSeconds();
  448.                 m_startTime = m_lastFrameTime;
  449.                 ReadDestinationPosFromInput(pActInfo);
  450.                 m_easeOutDistance = GetPortFloat(pActInfo, IN_EASEOUT);
  451.                 m_easeInDistance = GetPortFloat(pActInfo, IN_EASEIN);
  452.                 ReadSpeedFromInput(pActInfo);
  453.                 if (m_easeOutDistance < 0.0f) m_easeOutDistance = 0.0f;
  454.                 m_stopping = false;
  455.                 m_bActive = true;
  456.                 m_bUsePhysicUpdate = CanUsePhysicsUpdate(pEnt);
  457.  
  458.                 pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  459.  
  460.                 ActivateOutput(pActInfo, OUT_START, true);
  461.         }
  462.  
  463.         //////////////////////////////////////////////////////////////////////////
  464.         void Stop(SActivationInfo* pActInfo)
  465.         {
  466.                 pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  467.  
  468.                 if (m_bActive)
  469.                 {
  470.                         m_bActive = false;
  471.                         ActivateOutput(pActInfo, OUT_DONE, true);
  472.  
  473.                         if (m_bUsePhysicUpdate)
  474.                         {
  475.                                 if (IEntity* pEntity = pActInfo->pEntity)
  476.                                 {
  477.                                         if (IPhysicalEntity* pPhysEntity = pEntity->GetPhysics())
  478.                                         {
  479.                                                 pe_action_set_velocity setVel;
  480.                                                 setVel.v = ZERO;
  481.                                                 pPhysEntity->Action(&setVel);
  482.                                         }
  483.                                 }
  484.                         }
  485.                 }
  486.                 ActivateOutput(pActInfo, OUT_STOP, true);
  487.         }
  488.  
  489.         virtual void GetMemoryUsage(ICrySizer* s) const
  490.         {
  491.                 s->Add(*this);
  492.         }
  493. };
  494.  
  495. const float CMoveEntityTo::EASE_MARGIN_FACTOR = 0.2f;  // the eases dont go to/from speed 0, they go to/from this fraction of the max speed.
  496.  
  497. REGISTER_FLOW_NODE("Movement:MoveEntityTo", CMoveEntityTo);
  498.  
downloadOwnerLinearInterpolatorNode.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