KrakenEffectorComponent.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "KrakenEffectorComponent.h"
  9. #include "ApplePickingNotifications.h"
  10. #include "Manipulator/ManipulatorRequestBus.h"
  11. #include "PickingStructs.h"
  12. #include "ROS2/VehicleDynamics/VehicleInputControlBus.h"
  13. #include <AzCore/Component/Entity.h>
  14. #include <AzCore/Component/ComponentApplicationBus.h>
  15. #include <AzCore/Component/TransformBus.h>
  16. #include <AzCore/Serialization/EditContext.h>
  17. #include <AzCore/Serialization/EditContextConstants.inl>
  18. #include <AzCore/Serialization/SerializeContext.h>
  19. #include <AzFramework/Physics/Common/PhysicsSimulatedBody.h>
  20. #include <AzFramework/Physics/RigidBodyBus.h>
  21. #include <LmbrCentral/Shape/BoxShapeComponentBus.h>
  22. namespace AppleKraken
  23. {
  24. namespace DebugStateTransit
  25. {
  26. static const AZStd::unordered_map<EffectorState, const char*> kMapToString{ { EffectorState::INVALID, "INVALID" },
  27. { EffectorState::IDLE, "IDLE" },
  28. { EffectorState::PREPARED, "PREPARED" },
  29. { EffectorState::PICKING, "PICKING" },
  30. { EffectorState::PICKING_STABILIZE, "PICKING_STABILIZE" },
  31. { EffectorState::RETRIEVING, "RETRIEVING" },
  32. { EffectorState::RETRIEVING_NOSE, "RETRIEVING_NOSE" },
  33. { EffectorState::RETRIEVING_STABILIZE,
  34. "RETRIEVING_STABILIZE" } };
  35. // TODO - this is a debug space for a stub implementation. Proper: a state transition machine with lambdas.
  36. AZStd::string StateTransitionString(EffectorState current, EffectorState next)
  37. {
  38. return AZStd::string::format("state transition %s -> %s\n", kMapToString.at(current), kMapToString.at(next));
  39. }
  40. } // namespace DebugStateTransit
  41. KrakenEffectorComponent::KrakenEffectorComponent()
  42. {
  43. InitializeStateProperties();
  44. }
  45. void KrakenEffectorComponent::Activate()
  46. {
  47. ApplePickingRequestBus::Handler::BusConnect(GetEntityId());
  48. AZ::TickBus::Handler::BusConnect();
  49. EBUS_EVENT_ID_RESULT(m_appleProbe, m_manipulatorEntity, ManipulatorRequestBus, GetEffectorEntity);
  50. EBUS_EVENT_ID_RESULT(m_restEntityId, m_manipulatorEntity, ManipulatorRequestBus, GetRestEntity);
  51. m_onTriggerHandleBeginHandler = AzPhysics::SimulatedBodyEvents::OnTriggerEnter::Handler(
  52. [&]([[maybe_unused]] AzPhysics::SimulatedBodyHandle bodyHandle, [[maybe_unused]] const AzPhysics::TriggerEvent& event)
  53. {
  54. const AZ::EntityId& e1 = event.m_otherBody->GetEntityId();
  55. const AZ::EntityId& e2 = event.m_triggerBody->GetEntityId();
  56. [[maybe_unused]] const AZ::EntityId& collideToEntityId = m_appleProbe == e1 ? e2 : e1;
  57. // AZStd::string entity_name;
  58. // AZ::ComponentApplicationBus::BroadcastResult(entity_name,
  59. // &AZ::ComponentApplicationRequests::GetEntityName, collideToEntityId);
  60. // AZ_Printf("m_onTriggerHandleBeginHandler", "Collission %s\n", entity_name.c_str());
  61. // AzPhysics::SimulatedBody* collideToEntityId = this->GetEntityId() == e1 ? event.m_triggerBody : event.m_otherBody;}
  62. if (m_currentTask.m_appleEntityId == collideToEntityId)
  63. {
  64. AZ_TracePrintf("m_onTriggerHandleBeginHandler", " %s : m_onTriggerHandle to Apple!====================",
  65. GetEntity()->GetName().c_str());
  66. ApplePickingNotificationBus::Event(this->GetEntityId(),&ApplePickingNotifications::ApplePicked);
  67. if (m_effectorState == EffectorState::PICKING)
  68. {
  69. // start picking the apple
  70. BeginTransitionIfAcceptable(EffectorState::PICKING_STABILIZE);
  71. }
  72. }
  73. if (m_restEntityId == collideToEntityId)
  74. {
  75. AZ_TracePrintf("m_onTriggerHandleBeginHandler", "%s : m_onTriggerHandle to Rest!====================",
  76. GetEntity()->GetName().c_str());
  77. if (m_effectorState == EffectorState::RETRIEVING || m_effectorState == EffectorState::RETRIEVING_NOSE )
  78. {
  79. // start picking the apple
  80. BeginTransitionIfAcceptable(EffectorState::RETRIEVING_STABILIZE);
  81. }
  82. }
  83. });
  84. }
  85. void KrakenEffectorComponent::Deactivate()
  86. {
  87. AZ::TickBus::Handler::BusDisconnect();
  88. ApplePickingRequestBus::Handler::BusDisconnect();
  89. }
  90. void KrakenEffectorComponent::Reflect(AZ::ReflectContext* context)
  91. {
  92. if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
  93. {
  94. serialize->Class<KrakenEffectorComponent, AZ::Component>()
  95. ->Version(4)
  96. ->Field("ReachEntity", &KrakenEffectorComponent::m_reachEntity)
  97. ->Field("ManipulatorEntity", &KrakenEffectorComponent::m_manipulatorEntity)
  98. ->Field("RootManipulatorFreeze", &KrakenEffectorComponent::m_rootEntityToFreeze)
  99. ->Field("BaseLinkToKinematic", &KrakenEffectorComponent::m_baseLinkToKinematic)
  100. ->Field("PickStabilizeTime", &KrakenEffectorComponent::m_stabilize_time)
  101. ->Field("MaxPickingTime", &KrakenEffectorComponent::m_maxPickingTime);
  102. if (AZ::EditContext* ec = serialize->GetEditContext())
  103. {
  104. ec->Class<KrakenEffectorComponent>("Kraken Effector", "Manipulator component for picking apples")
  105. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  106. ->Attribute(AZ::Edit::Attributes::Category, "AppleKraken")
  107. ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game"))
  108. ->DataElement(
  109. AZ::Edit::UIHandlers::EntityId,
  110. &KrakenEffectorComponent::m_reachEntity,
  111. "Kraken Reach entity",
  112. "Kraken entity with box shape to set reach area")
  113. ->DataElement(
  114. AZ::Edit::UIHandlers::EntityId,
  115. &KrakenEffectorComponent::m_manipulatorEntity,
  116. "Entity with manipulator",
  117. "The entity that has a component handling events from ManipulatorRequestBus")
  118. ->DataElement(
  119. AZ::Edit::UIHandlers::EntityId,
  120. &KrakenEffectorComponent::m_rootEntityToFreeze,
  121. "RootManipulatorFreeze",
  122. "RootManipulatorFreeze to freeze during robot movement")
  123. ->DataElement(
  124. AZ::Edit::UIHandlers::EntityId,
  125. &KrakenEffectorComponent::m_baseLinkToKinematic,
  126. "BaseLinkToKinematic",
  127. "BaseLinkToKinematic during manipulator movement")
  128. ->DataElement(
  129. AZ::Edit::UIHandlers::EntityId,
  130. &KrakenEffectorComponent::m_stabilize_time,
  131. "PickStabilizeTime",
  132. "PickStabilizeTime")
  133. ->DataElement(
  134. AZ::Edit::UIHandlers::EntityId, &KrakenEffectorComponent::m_maxPickingTime, "MaxPickingTime", "MaxPickingTime")
  135. ->Attribute(AZ::Edit::Attributes::AutoExpand, true);
  136. }
  137. }
  138. ManipulatorRequestHandler::Reflect(context);
  139. }
  140. void KrakenEffectorComponent::PrepareForPicking()
  141. {
  142. AZ_TracePrintf("KrakenEffectorComponent", "%s: PrepareForPicking\n", GetEntity()->GetName().c_str());
  143. BeginTransitionIfAcceptable(EffectorState::PREPARED);
  144. }
  145. void KrakenEffectorComponent::PickApple(const PickAppleTask& appleTask)
  146. {
  147. AZ_TracePrintf("KrakenEffectorComponent", "%s: PickApple\n", GetEntity()->GetName().c_str());
  148. // TODO - handle appleTask
  149. m_currentTask = appleTask;
  150. ManipulatorRequestBus::Event(m_manipulatorEntity, &ManipulatorRequest::PickApple, appleTask.m_middle);
  151. BeginTransitionIfAcceptable(EffectorState::PICKING);
  152. }
  153. void KrakenEffectorComponent::FinishPicking()
  154. {
  155. AZ_TracePrintf("KrakenEffectorComponent", "%s : FinishPicking\n", GetEntity()->GetName().c_str());
  156. BeginTransitionIfAcceptable(EffectorState::IDLE);
  157. }
  158. PickingState KrakenEffectorComponent::GetEffectorState()
  159. {
  160. PickingState state;
  161. state.m_effectorState = m_effectorState;
  162. state.m_taskProgress = 0.0f; // TODO
  163. state.m_description = DebugStateTransit::kMapToString.at(m_effectorState);
  164. if (m_currentTask.IsValid())
  165. {
  166. state.m_currentTask = m_currentTask;
  167. }
  168. return state;
  169. }
  170. AZ::Obb KrakenEffectorComponent::GetEffectorReachArea()
  171. {
  172. AZ_TracePrintf("KrakenEffectorComponent", "%s: GetEffectorReachArea\n", GetEntity()->GetName().c_str());
  173. AZ::Obb reachArea;
  174. if (m_reachEntity.IsValid())
  175. {
  176. AZ::Transform targetTM = AZ::Transform::CreateIdentity();
  177. AZ::TransformBus::EventResult(targetTM, m_reachEntity, &AZ::TransformBus::Events::GetWorldTM);
  178. AZ::Vector3 dimensions = AZ::Vector3{ 0.f };
  179. LmbrCentral::BoxShapeComponentRequestsBus::EventResult(
  180. dimensions, m_reachEntity, &LmbrCentral::BoxShapeComponentRequests::GetBoxDimensions);
  181. if (!dimensions.IsZero())
  182. {
  183. AZ_Printf("KrakenEffectorComponent", "OurEffectorReachArea :");
  184. AZ_Printf(
  185. "KrakenEffectorComponent", " local dimensions : %f %f %f", dimensions.GetX(), dimensions.GetY(), dimensions.GetZ());
  186. AZ_Printf(
  187. "KrakenEffectorComponent",
  188. " transform - rot : %f %f %f %f",
  189. targetTM.GetRotation().GetX(),
  190. targetTM.GetRotation().GetY(),
  191. targetTM.GetRotation().GetZ(),
  192. targetTM.GetRotation().GetW());
  193. AZ_Printf(
  194. "KrakenEffectorComponent",
  195. " transform - pos : %f %f %f",
  196. targetTM.GetTranslation().GetX(),
  197. targetTM.GetTranslation().GetY(),
  198. targetTM.GetTranslation().GetZ());
  199. reachArea.SetHalfLengths(dimensions / 2);
  200. reachArea.SetPosition(targetTM.GetTranslation());
  201. reachArea.SetRotation(targetTM.GetRotation());
  202. return reachArea;
  203. }
  204. AZ_Warning(
  205. "KrakenEffectorComponent", true, "Reach entity %s does not have BoxShapeComponent!", m_reachEntity.ToString().c_str());
  206. }
  207. AZ_Warning("KrakenEffectorComponent", true, "GetEffectorReachArea - returning invalid reach");
  208. reachArea.SetHalfLengths(AZ::Vector3{ 0, 0, 0 });
  209. reachArea.SetPosition(AZ::Vector3{ 0, 0, 0 }); /// TODO - get it from entity With box
  210. return reachArea;
  211. }
  212. void KrakenEffectorComponent::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
  213. {
  214. m_currentStateTransitionTime += deltaTime;
  215. GetCurrentStateAction()();
  216. if (m_effectorState == m_effectorTargetState)
  217. { // //TODO - nothing to do in stub version
  218. return;
  219. }
  220. // State transition
  221. AZ_TracePrintf(
  222. "KrakenEffectorComponent", "%s : %s", GetEntity()->GetName().c_str(), DebugStateTransit::StateTransitionString(m_effectorState, m_effectorTargetState).c_str());
  223. m_currentStateTransitionTime = 0.0f;
  224. // Update state
  225. auto transitionAction = GetCurrentTransitionAction();
  226. m_effectorState = m_effectorTargetState;
  227. transitionAction();
  228. if (!m_registeredCallback)
  229. {
  230. auto* physicsSystem = AZ::Interface<AzPhysics::SystemInterface>::Get();
  231. auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get();
  232. auto [physicScene, physicBody] = physicsSystem->FindAttachedBodyHandleFromEntityId(m_appleProbe);
  233. if (physicBody != AzPhysics::InvalidSimulatedBodyHandle && physicScene != AzPhysics::InvalidSceneHandle)
  234. {
  235. AzPhysics::SimulatedBody* simulated_body = sceneInterface->GetSimulatedBodyFromHandle(physicScene, physicBody);
  236. simulated_body->RegisterOnTriggerEnterHandler(m_onTriggerHandleBeginHandler);
  237. m_registeredCallback = true;
  238. }
  239. }
  240. }
  241. void KrakenEffectorComponent::LockManipulator(bool locked)
  242. {
  243. AZStd::vector<AZ::EntityId> descendants;
  244. AZ::TransformBus::EventResult(descendants, m_rootEntityToFreeze, &AZ::TransformBus::Events::GetAllDescendants);
  245. descendants.push_back(m_rootEntityToFreeze);
  246. if (is_manipulator_locked != locked)
  247. {
  248. if (locked) {
  249. AZ_Printf("KrakenEffectorComponent", "Locking : %s\n", GetEntity()->GetName().c_str());
  250. }
  251. else{
  252. AZ_Printf("KrakenEffectorComponent", "Unlocking : %s\n", GetEntity()->GetName().c_str());
  253. }
  254. for (auto& descadant : descendants)
  255. {
  256. using VehicleBus = VehicleDynamics::VehicleInputControlRequestBus;
  257. if (locked)
  258. {
  259. // Lock manipulator, make base_link not kinematic anymore
  260. Physics::RigidBodyRequestBus::Event(descadant, &Physics::RigidBodyRequestBus::Events::DisablePhysics);
  261. Physics::RigidBodyRequestBus::Event(m_baseLinkToKinematic, &Physics::RigidBodyRequestBus::Events::SetKinematic, false);
  262. VehicleBus::Event(m_baseLinkToKinematic, &VehicleBus::Events::SetDisableVehicleDynamics, false);
  263. }
  264. else
  265. {
  266. // loose manipulator, make base_link kinematic
  267. Physics::RigidBodyRequestBus::Event(descadant, &Physics::RigidBodyRequestBus::Events::EnablePhysics);
  268. Physics::RigidBodyRequestBus::Event(m_baseLinkToKinematic, &Physics::RigidBodyRequestBus::Events::SetKinematic, true);
  269. VehicleBus::Event(m_baseLinkToKinematic, &VehicleBus::Events::SetDisableVehicleDynamics, true);
  270. }
  271. }
  272. is_manipulator_locked = locked;
  273. }
  274. }
  275. bool KrakenEffectorComponent::IsTransitionValid(EffectorState targetState) const
  276. {
  277. AZ_Assert(m_effectorState != EffectorState::INVALID, "Effector is in an invalid state! Unable to access transition properties.");
  278. return m_stateProperties.m_allowedTransitions.contains(AZStd::make_pair(m_effectorState, targetState));
  279. }
  280. bool KrakenEffectorComponent::IsTransitionAcceptable(EffectorState targetState) const
  281. {
  282. if (m_effectorState == EffectorState::PICKING && m_effectorState == EffectorState::PICKING)
  283. {
  284. // allow this non-existing state transition without error
  285. return true;
  286. }
  287. if (m_effectorState != m_effectorTargetState)
  288. {
  289. AZ_Error(
  290. "KrakenEffectorComponent",
  291. false,
  292. "%s: Unable to accept request: currently realizing %s", GetEntity()->GetName().c_str(),
  293. DebugStateTransit::StateTransitionString(m_effectorState, m_effectorTargetState).c_str());
  294. return false;
  295. }
  296. if (!IsTransitionValid(targetState))
  297. {
  298. AZ_Error(
  299. "KrakenEffectorComponent",
  300. false,
  301. "%s: Invalid state transition %s",GetEntity()->GetName().c_str(),
  302. DebugStateTransit::StateTransitionString(m_effectorState, m_effectorTargetState).c_str());
  303. return false;
  304. }
  305. return true;
  306. }
  307. void KrakenEffectorComponent::BeginTransitionIfAcceptable(EffectorState targetState)
  308. {
  309. if (IsTransitionAcceptable(targetState))
  310. {
  311. m_currentStateTransitionTime = 0.0f;
  312. m_effectorTargetState = targetState;
  313. }
  314. }
  315. void KrakenEffectorComponent::InitializeStateProperties()
  316. {
  317. m_stateProperties.m_stateActions = {
  318. { EffectorState::IDLE,
  319. [this]()
  320. {
  321. LockManipulator(true);
  322. } },
  323. { EffectorState::PREPARED,
  324. []()
  325. {
  326. } },
  327. { EffectorState::PICKING,
  328. [this]()
  329. {
  330. if (m_currentStateTransitionTime > m_maxPickingTime)
  331. {
  332. AZ_Printf("m_onTriggerHandleBeginHandler", "%s : Failed to retrieve apple--------------------\n", GetEntity()->GetName().c_str());
  333. BeginTransitionIfAcceptable(EffectorState::RETRIEVING_FAILED);
  334. }
  335. } },
  336. { EffectorState::PICKING_STABILIZE,
  337. [this]()
  338. {
  339. if (m_currentStateTransitionTime > m_stabilize_time)
  340. {
  341. BeginTransitionIfAcceptable(EffectorState::RETRIEVING_NOSE);
  342. }
  343. } },
  344. { EffectorState::RETRIEVING_NOSE,
  345. [this]()
  346. {
  347. bool result;
  348. EBUS_EVENT_ID_RESULT(result, m_manipulatorEntity, ManipulatorRequestBus, IsNoseRetreived);
  349. if (result)
  350. {
  351. BeginTransitionIfAcceptable(EffectorState::RETRIEVING);
  352. }
  353. } },
  354. { EffectorState::RETRIEVING_FAILED,
  355. [this]()
  356. {
  357. bool result;
  358. EBUS_EVENT_ID_RESULT(result, m_manipulatorEntity, ManipulatorRequestBus, IsNoseRetreived);
  359. if (result)
  360. {
  361. BeginTransitionIfAcceptable(EffectorState::PREPARED);
  362. }
  363. } },
  364. {EffectorState::RETRIEVING,
  365. [this]() {
  366. // Continue if manipulator retraction was blocked
  367. if (m_currentStateTransitionTime > m_maxRetrieveTime) {
  368. BeginTransitionIfAcceptable(EffectorState::RETRIEVING_STABILIZE);
  369. }
  370. } },
  371. { EffectorState::RETRIEVING_STABILIZE,
  372. [this]()
  373. {
  374. if (m_currentStateTransitionTime > m_stabilize_time)
  375. {
  376. BeginTransitionIfAcceptable(EffectorState::PREPARED);
  377. }
  378. } }
  379. };
  380. m_stateProperties.m_allowedTransitions = {
  381. {
  382. { EffectorState::IDLE, EffectorState::PREPARED },
  383. [this]()
  384. {
  385. LockManipulator(false);
  386. ApplePickingNotificationBus::Event(GetEntityId(),&ApplePickingNotifications::EffectorReadyForPicking);
  387. },
  388. },
  389. {
  390. { EffectorState::PREPARED, EffectorState::PICKING },
  391. []()
  392. {
  393. },
  394. },
  395. {
  396. { EffectorState::PICKING, EffectorState::PICKING_STABILIZE },
  397. []()
  398. {
  399. },
  400. },
  401. {
  402. { EffectorState::PICKING_STABILIZE, EffectorState::RETRIEVING_NOSE },
  403. [this]()
  404. {
  405. if (!m_currentTask.IsValid())
  406. {
  407. AZ_Error("KrakenEffectorComponent", true, "%s : No valid task for current picking!",GetEntity()->GetName().c_str());
  408. return;
  409. }
  410. ManipulatorRequestBus::Event(m_manipulatorEntity, &ManipulatorRequest::RetrieveNose);
  411. },
  412. },
  413. {
  414. { EffectorState::RETRIEVING_NOSE, EffectorState::RETRIEVING },
  415. [this]()
  416. {
  417. ManipulatorRequestBus::Event(m_manipulatorEntity, &ManipulatorRequest::Retrieve);
  418. },
  419. },
  420. { // on skip
  421. { EffectorState::RETRIEVING_NOSE, EffectorState::RETRIEVING_STABILIZE },
  422. [this]()
  423. {
  424. ManipulatorRequestBus::Event(m_manipulatorEntity, &ManipulatorRequest::Retrieve);
  425. },
  426. },
  427. {
  428. { EffectorState::RETRIEVING, EffectorState::RETRIEVING_STABILIZE },
  429. []()
  430. {
  431. },
  432. },
  433. {
  434. { EffectorState::RETRIEVING_FAILED, EffectorState::PREPARED },
  435. [this]()
  436. {
  437. ApplePickingNotificationBus::Event(this->GetEntityId(),&ApplePickingNotifications::PickingFailed, "Timeout");
  438. },
  439. },
  440. {
  441. { EffectorState::RETRIEVING_STABILIZE, EffectorState::PREPARED },
  442. [this]()
  443. {
  444. ApplePickingNotificationBus::Event(GetEntityId(),&ApplePickingNotifications::AppleRetrieved);
  445. },
  446. },
  447. {
  448. { EffectorState::PREPARED, EffectorState::IDLE },
  449. []()
  450. {
  451. },
  452. },
  453. {
  454. { EffectorState::PICKING, EffectorState::IDLE },
  455. [this]()
  456. {
  457. // apple picking was finished with timeout
  458. ManipulatorRequestBus::Event(m_manipulatorEntity, &ManipulatorRequest::Retrieve);
  459. },
  460. },
  461. {
  462. { EffectorState::PICKING, EffectorState::RETRIEVING_FAILED },
  463. [this]()
  464. {
  465. ManipulatorRequestBus::Event(m_manipulatorEntity, &ManipulatorRequest::RetrieveNose);
  466. },
  467. },
  468. };
  469. }
  470. const AZStd::function<void()>& KrakenEffectorComponent::GetCurrentStateAction() const
  471. {
  472. AZ_Assert(m_effectorState != EffectorState::INVALID, "%s : Effector is in an invalid state! Unable to access state properties.",GetEntity()->GetName().c_str());
  473. return m_stateProperties.m_stateActions.at(m_effectorState);
  474. }
  475. const AZStd::function<void()>& KrakenEffectorComponent::GetCurrentTransitionAction() const
  476. {
  477. return m_stateProperties.m_allowedTransitions.at(AZStd::make_pair(m_effectorState, m_effectorTargetState));
  478. }
  479. } // namespace AppleKraken