NetworkAnimationComponent.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0 OR MIT
  5. *
  6. */
  7. #include <Source/Components/NetworkAnimationComponent.h>
  8. #include <Multiplayer/Components/NetworkCharacterComponent.h>
  9. #include <Source/Components/NetworkSimplePlayerCameraComponent.h>
  10. #include <Source/Components/NetworkPlayerMovementComponent.h>
  11. #include <Integration/AnimGraphComponentBus.h>
  12. #include <Integration/AnimationBus.h>
  13. #include <Integration/AnimGraphNetworkingBus.h>
  14. #include <AzCore/Component/TransformBus.h>
  15. #if AZ_TRAIT_CLIENT
  16. #include <DebugDraw/DebugDrawBus.h>
  17. #endif
  18. namespace MultiplayerSample
  19. {
  20. #ifndef AZ_RELEASE_BUILD
  21. AZ_CVAR(bool, cl_drawAimTarget, false, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "When enabled draws a sphere at the character aim target.");
  22. #endif // AZ_RELEASE_BUILD
  23. void NetworkAnimationComponent::NetworkAnimationComponent::Reflect(AZ::ReflectContext* context)
  24. {
  25. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  26. if (serializeContext)
  27. {
  28. serializeContext->Class<NetworkAnimationComponent, NetworkAnimationComponentBase>()
  29. ->Version(1);
  30. }
  31. NetworkAnimationComponentBase::Reflect(context);
  32. }
  33. NetworkAnimationComponent::NetworkAnimationComponent()
  34. : m_preRenderEventHandler([this](float deltaTime) {OnPreRender(deltaTime); })
  35. {
  36. ;
  37. }
  38. void NetworkAnimationComponent::OnInit()
  39. {
  40. ;
  41. }
  42. void NetworkAnimationComponent::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  43. {
  44. m_actorRequests = EMotionFX::Integration::ActorComponentRequestBus::FindFirstHandler(GetEntityId());
  45. m_networkRequests = EMotionFX::AnimGraphComponentNetworkRequestBus::FindFirstHandler(GetEntityId());
  46. m_animationGraph = EMotionFX::Integration::AnimGraphComponentRequestBus::FindFirstHandler(GetEntityId());
  47. EMotionFX::Integration::ActorComponentNotificationBus::Handler::BusConnect(GetEntityId());
  48. EMotionFX::Integration::AnimGraphComponentNotificationBus::Handler::BusConnect(GetEntityId());
  49. GetNetBindComponent()->AddEntityPreRenderEventHandler(m_preRenderEventHandler);
  50. }
  51. void NetworkAnimationComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  52. {
  53. EMotionFX::Integration::ActorComponentNotificationBus::Handler::BusDisconnect();
  54. }
  55. int32_t NetworkAnimationComponent::GetBoneIdByName(const char* boneName) const
  56. {
  57. if (m_actorRequests != nullptr)
  58. {
  59. return static_cast<int32_t>(m_actorRequests->GetJointIndexByName(boneName));
  60. }
  61. return InvalidBoneId;
  62. }
  63. bool NetworkAnimationComponent::GetJointTransformByName(const char* jointName, AZ::Transform& outJointTransform) const
  64. {
  65. if (m_actorRequests == nullptr)
  66. {
  67. return false;
  68. }
  69. const int32_t jointId = static_cast<int32_t>(m_actorRequests->GetJointIndexByName(jointName));
  70. return GetJointTransformById(jointId, outJointTransform);
  71. }
  72. bool NetworkAnimationComponent::GetJointTransformById(int32_t jointId, AZ::Transform& outJointTransform) const
  73. {
  74. if ((m_actorRequests == nullptr) || (jointId == InvalidBoneId))
  75. {
  76. return false;
  77. }
  78. outJointTransform = m_actorRequests->GetJointTransform(jointId, EMotionFX::Integration::Space::WorldSpace);
  79. return true;
  80. }
  81. void NetworkAnimationComponent::OnPreRender(float deltaTime)
  82. {
  83. if (m_animationGraph == nullptr || m_networkRequests == nullptr)
  84. {
  85. return;
  86. }
  87. // velocity or movement direction are necessary for movement
  88. if (m_velocityParamId == InvalidParamIndex && m_movementDirectionParamId == InvalidParamIndex)
  89. {
  90. m_velocityParamId = m_animationGraph->FindParameterIndex(GetVelocityParamName().c_str());
  91. m_movementDirectionParamId = m_animationGraph->FindParameterIndex(GetMovementDirectionParamName().c_str());
  92. m_movementSpeedParamId = m_animationGraph->FindParameterIndex(GetMovementSpeedParamName().c_str());
  93. m_aimTargetParamId = m_animationGraph->FindParameterIndex(GetAimTargetParamName().c_str());
  94. m_crouchParamId = m_animationGraph->FindParameterIndex(GetCrouchParamName().c_str());
  95. m_aimingParamId = m_animationGraph->FindParameterIndex(GetAimingParamName().c_str());
  96. m_shootParamId = m_animationGraph->FindParameterIndex(GetShootParamName().c_str());
  97. m_jumpParamId = m_animationGraph->FindParameterIndex(GetJumpParamName().c_str());
  98. m_fallParamId = m_animationGraph->FindParameterIndex(GetFallParamName().c_str());
  99. m_landParamId = m_animationGraph->FindParameterIndex(GetLandParamName().c_str());
  100. m_hitParamId = m_animationGraph->FindParameterIndex(GetHitParamName().c_str());
  101. m_deathParamId = m_animationGraph->FindParameterIndex(GetDeathParamName().c_str());
  102. }
  103. {
  104. // velocity and direction/speed based animations
  105. // base the anim on the player's generated velocity, not velocity from external sources
  106. const AZ::Transform worldTm = GetEntity()->GetTransform()->GetWorldTM();
  107. const float maxSpeed = GetNetworkPlayerMovementComponent()->GetSprintSpeed();
  108. AZ::Vector3 velocity = GetNetworkPlayerMovementComponent()->GetSelfGeneratedVelocity();
  109. AZ::Vector2 velocity2d = AZ::Vector2(velocity.GetX(), velocity.GetY());
  110. if (GetVelocityIsLocal())
  111. {
  112. velocity = worldTm.GetInverse().TransformVector(velocity);
  113. velocity2d = AZ::Vector2(velocity.GetX(), velocity.GetY());
  114. }
  115. const float speed = velocity2d.GetLength() / maxSpeed;
  116. if (m_velocityParamId != InvalidParamIndex)
  117. {
  118. const bool aiming = GetActiveAnimStates().GetBit(aznumeric_cast<uint32_t>(CharacterAnimState::Aiming));
  119. if (GetTurningEnabled() && !aiming)
  120. {
  121. const float turnAmount = velocity2d.GetX();
  122. m_animationGraph->SetParameterVector2(m_velocityParamId, AZ::Vector2(turnAmount, speed));
  123. }
  124. else
  125. {
  126. m_animationGraph->SetParameterVector2(m_velocityParamId, velocity2d / maxSpeed);
  127. }
  128. }
  129. else if (m_movementDirectionParamId != InvalidParamIndex && m_movementSpeedParamId != InvalidParamIndex)
  130. {
  131. if (speed != 0.f)
  132. {
  133. const AZ::Vector3 movementDirection = velocity.GetNormalized();
  134. m_animationGraph->SetParameterVector2(m_movementDirectionParamId, AZ::Vector2(movementDirection.GetX(), movementDirection.GetY()));
  135. }
  136. else
  137. {
  138. const AZ::Vector3 forward = worldTm.GetBasisY();
  139. m_animationGraph->SetParameterVector2(m_movementDirectionParamId, AZ::Vector2(forward.GetX(), forward.GetY()));
  140. }
  141. m_animationGraph->SetParameterFloat(m_movementSpeedParamId, speed);
  142. }
  143. }
  144. if (m_aimTargetParamId != InvalidParamIndex)
  145. {
  146. AZ::Vector3 baseCameraOffset;
  147. AZ::Interface<AZ::IConsole>::Get()->GetCvarValue("cl_cameraOffset", baseCameraOffset);
  148. const AZ::Vector3 cameraOffset = AZ::Vector3(baseCameraOffset.GetX(), 0.f, baseCameraOffset.GetZ());
  149. const AZ::Transform worldTm = GetEntity()->GetTransform()->GetWorldTM();
  150. const AZ::Vector3 aimAngles = GetNetworkSimplePlayerCameraComponent()->GetAimAngles();
  151. // use the player model forward but the aim pitch to get the smoothest motion
  152. // currently, aim angles is updated later in the frame causing a 1 frame jitter
  153. const AZ::Quaternion aimRotation = worldTm.GetRotation() *AZ::Quaternion::CreateRotationX(aimAngles.GetX());
  154. const AZ::Vector3 fwd = AZ::Vector3::CreateAxisY();
  155. const AZ::Vector3 aimTarget = worldTm.GetTranslation() + worldTm.GetRotation().TransformVector(cameraOffset) + aimRotation.TransformVector(fwd * 5.f);
  156. m_animationGraph->SetParameterVector3(m_aimTargetParamId, aimTarget);
  157. #ifndef AZ_RELEASE_BUILD
  158. #if AZ_TRAIT_CLIENT
  159. if (cl_drawAimTarget)
  160. {
  161. if (auto debugDraw = DebugDraw::DebugDrawRequestBus::FindFirstHandler(); debugDraw != nullptr)
  162. {
  163. debugDraw->DrawSphereAtLocation(aimTarget, 0.1f, AZ::Colors::Red, 0.f);
  164. }
  165. }
  166. #endif
  167. #endif // AZ_RELEASE_BUILD
  168. }
  169. if (m_crouchParamId != InvalidParamIndex)
  170. {
  171. const bool crouching = GetActiveAnimStates().GetBit(aznumeric_cast<uint32_t>(CharacterAnimState::Crouching));
  172. m_animationGraph->SetParameterBool(m_crouchParamId, crouching);
  173. }
  174. if (m_aimingParamId != InvalidParamIndex)
  175. {
  176. const bool aiming = GetActiveAnimStates().GetBit(aznumeric_cast<uint32_t>(CharacterAnimState::Aiming));
  177. m_animationGraph->SetParameterBool(m_aimingParamId, aiming);
  178. }
  179. if (m_shootParamId != InvalidParamIndex)
  180. {
  181. const bool shooting = GetActiveAnimStates().GetBit(aznumeric_cast<uint32_t>(CharacterAnimState::Shooting));
  182. m_animationGraph->SetParameterBool(m_shootParamId, shooting);
  183. }
  184. if (m_jumpParamId != InvalidParamIndex)
  185. {
  186. const bool jumping = GetActiveAnimStates().GetBit(aznumeric_cast<uint32_t>(CharacterAnimState::Jumping));
  187. m_animationGraph->SetParameterBool(m_jumpParamId, jumping);
  188. }
  189. if (m_fallParamId != InvalidParamIndex)
  190. {
  191. const bool falling = GetActiveAnimStates().GetBit(aznumeric_cast<uint32_t>(CharacterAnimState::Falling));
  192. m_animationGraph->SetParameterBool(m_fallParamId, falling);
  193. }
  194. if (m_landParamId != InvalidParamIndex)
  195. {
  196. const bool landing = GetActiveAnimStates().GetBit(aznumeric_cast<uint32_t>(CharacterAnimState::Landing));
  197. m_animationGraph->SetParameterBool(m_landParamId, landing);
  198. }
  199. if (m_hitParamId != InvalidParamIndex)
  200. {
  201. const bool hit = GetActiveAnimStates().GetBit(aznumeric_cast<uint32_t>(CharacterAnimState::Hit));
  202. m_animationGraph->SetParameterBool(m_hitParamId, hit);
  203. }
  204. if (m_deathParamId != InvalidParamIndex)
  205. {
  206. const bool dead = GetActiveAnimStates().GetBit(aznumeric_cast<uint32_t>(CharacterAnimState::Dying));
  207. m_animationGraph->SetParameterBool(m_deathParamId, dead);
  208. }
  209. m_networkRequests->UpdateActorExternal(deltaTime);
  210. }
  211. void NetworkAnimationComponent::OnActorInstanceCreated([[maybe_unused]] EMotionFX::ActorInstance* actorInstance)
  212. {
  213. m_actorRequests = EMotionFX::Integration::ActorComponentRequestBus::FindFirstHandler(GetEntityId());
  214. }
  215. void NetworkAnimationComponent::OnActorInstanceDestroyed([[maybe_unused]] EMotionFX::ActorInstance* actorInstance)
  216. {
  217. m_actorRequests = nullptr;
  218. }
  219. void NetworkAnimationComponent::OnAnimGraphInstanceCreated([[maybe_unused]] EMotionFX::AnimGraphInstance* animGraphInstance)
  220. {
  221. // We don't need any more notifications
  222. EMotionFX::Integration::AnimGraphComponentNotificationBus::Handler::BusDisconnect();
  223. // Disable automatic EMotionFX updates of transform, network has control
  224. if (m_actorRequests)
  225. {
  226. m_actorRequests->EnableInstanceUpdate(false);
  227. }
  228. }
  229. }