NetworkPlayerMovementComponent.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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/NetworkPlayerMovementComponent.h>
  8. #include <Source/Components/NetworkAiComponent.h>
  9. #include <Multiplayer/Components/NetworkCharacterComponent.h>
  10. #include <Source/Components/NetworkAnimationComponent.h>
  11. #include <Source/Components/NetworkSimplePlayerCameraComponent.h>
  12. #include <Multiplayer/Components/NetworkTransformComponent.h>
  13. #include <AzCore/Time/ITime.h>
  14. #include <AzFramework/Components/CameraBus.h>
  15. namespace ${SanitizedCppName}
  16. {
  17. AZ_CVAR(float, cl_WasdStickAccel, 5.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "The linear acceleration to apply to WASD inputs to simulate analog stick controls");
  18. AZ_CVAR(float, cl_AimStickScaleZ, 0.1f, nullptr, AZ::ConsoleFunctorFlags::Null, "The scaling to apply to aim and view adjustments");
  19. AZ_CVAR(float, cl_AimStickScaleX, 0.05f, nullptr, AZ::ConsoleFunctorFlags::Null, "The scaling to apply to aim and view adjustments");
  20. NetworkPlayerMovementComponentController::NetworkPlayerMovementComponentController(NetworkPlayerMovementComponent& parent)
  21. : NetworkPlayerMovementComponentControllerBase(parent)
  22. , m_updateAI{ [this] { UpdateAI(); }, AZ::Name{ "MovementControllerAi" } }
  23. {
  24. ;
  25. }
  26. void NetworkPlayerMovementComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  27. {
  28. NetworkAiComponent* networkAiComponent = GetParent().GetNetworkAiComponent();
  29. m_aiEnabled = (networkAiComponent != nullptr) ? networkAiComponent->GetEnabled() : false;
  30. if (m_aiEnabled)
  31. {
  32. m_updateAI.Enqueue(AZ::TimeMs{ 0 }, true);
  33. m_networkAiComponentController = GetNetworkAiComponentController();
  34. }
  35. else if (IsNetEntityRoleAutonomous())
  36. {
  37. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(MoveFwdEventId);
  38. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(MoveBackEventId);
  39. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(MoveLeftEventId);
  40. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(MoveRightEventId);
  41. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(SprintEventId);
  42. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(JumpEventId);
  43. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(CrouchEventId);
  44. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(LookLeftRightEventId);
  45. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(LookUpDownEventId);
  46. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(ZoomInEventId);
  47. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(ZoomOutEventId);
  48. }
  49. }
  50. void NetworkPlayerMovementComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  51. {
  52. if (IsNetEntityRoleAutonomous() && !m_aiEnabled)
  53. {
  54. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(MoveFwdEventId);
  55. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(MoveBackEventId);
  56. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(MoveLeftEventId);
  57. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(MoveRightEventId);
  58. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(SprintEventId);
  59. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(JumpEventId);
  60. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(CrouchEventId);
  61. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(LookLeftRightEventId);
  62. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(LookUpDownEventId);
  63. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(ZoomInEventId);
  64. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(ZoomOutEventId);
  65. }
  66. }
  67. void NetworkPlayerMovementComponentController::CreateInput(Multiplayer::NetworkInput& input, float deltaTime)
  68. {
  69. // Movement axis
  70. // Since we're on a keyboard, this adds a touch of an acceleration curve to the keyboard inputs
  71. // This is so that tapping the keyboard moves the virtual stick less than just holding it down
  72. m_forwardWeight = std::min<float>(m_forwardDown ? m_forwardWeight + cl_WasdStickAccel * deltaTime : 0.0f, 1.0f);
  73. m_leftWeight = std::min<float>(m_leftDown ? m_leftWeight + cl_WasdStickAccel * deltaTime : 0.0f, 1.0f);
  74. m_backwardWeight = std::min<float>(m_backwardDown ? m_backwardWeight + cl_WasdStickAccel * deltaTime : 0.0f, 1.0f);
  75. m_rightWeight = std::min<float>(m_rightDown ? m_rightWeight + cl_WasdStickAccel * deltaTime : 0.0f, 1.0f);
  76. // Inputs for your own component always exist
  77. NetworkPlayerMovementComponentNetworkInput* playerInput = input.FindComponentInput<NetworkPlayerMovementComponentNetworkInput>();
  78. playerInput->m_forwardAxis = StickAxis(m_forwardWeight - m_backwardWeight);
  79. playerInput->m_strafeAxis = StickAxis(m_leftWeight - m_rightWeight);
  80. // View Axis
  81. playerInput->m_viewYaw = MouseAxis(m_viewYaw);
  82. playerInput->m_viewPitch = MouseAxis(m_viewPitch);
  83. // Strafe input
  84. playerInput->m_sprint = m_sprinting;
  85. playerInput->m_jump = m_jumping;
  86. playerInput->m_crouch = m_crouching;
  87. // Just a note for anyone who is super confused by this, ResetCount is a predictable network property, it gets set on the client
  88. // through correction packets
  89. playerInput->m_resetCount = GetNetworkTransformComponentController()->GetResetCount();
  90. }
  91. void NetworkPlayerMovementComponentController::ProcessInput(Multiplayer::NetworkInput& input, float deltaTime)
  92. {
  93. // If the input reset count doesn't match the state's reset count it can mean two things:
  94. // 1) On the server: we were reset and we are now receiving inputs from the client for an old reset count
  95. // 2) On the client: we were reset and we are replaying old inputs after being corrected
  96. // In both cases we don't want to process these inputs
  97. NetworkPlayerMovementComponentNetworkInput* playerInput = input.FindComponentInput<NetworkPlayerMovementComponentNetworkInput>();
  98. if (playerInput->m_resetCount != GetNetworkTransformComponentController()->GetResetCount())
  99. {
  100. return;
  101. }
  102. GetNetworkAnimationComponentController()->ModifyActiveAnimStates().SetBit(
  103. aznumeric_cast<uint32_t>(CharacterAnimState::Sprinting), playerInput->m_sprint);
  104. GetNetworkAnimationComponentController()->ModifyActiveAnimStates().SetBit(
  105. aznumeric_cast<uint32_t>(CharacterAnimState::Jumping), playerInput->m_jump);
  106. GetNetworkAnimationComponentController()->ModifyActiveAnimStates().SetBit(
  107. aznumeric_cast<uint32_t>(CharacterAnimState::Crouching), playerInput->m_crouch);
  108. // Update orientation
  109. AZ::Vector3 aimAngles = GetNetworkSimplePlayerCameraComponentController()->GetAimAngles();
  110. aimAngles.SetZ(NormalizeHeading(aimAngles.GetZ() - playerInput->m_viewYaw * cl_AimStickScaleZ));
  111. aimAngles.SetX(NormalizeHeading(aimAngles.GetX() - playerInput->m_viewPitch * cl_AimStickScaleX));
  112. aimAngles.SetX(
  113. NormalizeHeading(AZ::GetClamp(aimAngles.GetX(), -AZ::Constants::QuarterPi * 0.75f, AZ::Constants::QuarterPi * 0.75f)));
  114. GetNetworkSimplePlayerCameraComponentController()->SetAimAngles(aimAngles);
  115. const AZ::Quaternion newOrientation = AZ::Quaternion::CreateRotationZ(aimAngles.GetZ());
  116. GetEntity()->GetTransform()->SetLocalRotationQuaternion(newOrientation);
  117. // Update velocity
  118. UpdateVelocity(*playerInput);
  119. GetNetworkCharacterComponentController()->TryMoveWithVelocity(GetVelocity(), deltaTime);
  120. }
  121. void NetworkPlayerMovementComponentController::UpdateVelocity(const NetworkPlayerMovementComponentNetworkInput& playerInput)
  122. {
  123. const float fwdBack = playerInput.m_forwardAxis;
  124. const float leftRight = playerInput.m_strafeAxis;
  125. float speed = 0.0f;
  126. if (playerInput.m_crouch)
  127. {
  128. speed = GetCrouchSpeed();
  129. }
  130. else if (fwdBack < 0.0f)
  131. {
  132. speed = GetReverseSpeed();
  133. }
  134. else
  135. {
  136. if (playerInput.m_sprint)
  137. {
  138. speed = GetSprintSpeed();
  139. }
  140. else
  141. {
  142. speed = GetWalkSpeed();
  143. }
  144. }
  145. // Not moving?
  146. if (fwdBack == 0.0f && leftRight == 0.0f)
  147. {
  148. SetVelocity(AZ::Vector3::CreateZero());
  149. }
  150. else
  151. {
  152. const float stickInputAngle = AZ::Atan2(leftRight, fwdBack);
  153. const float currentHeading = GetNetworkTransformComponentController()->GetRotation().GetEulerRadians().GetZ();
  154. const float targetHeading =
  155. NormalizeHeading(currentHeading + stickInputAngle); // Update current heading with stick input angles
  156. const AZ::Vector3 fwd = AZ::Vector3::CreateAxisY();
  157. SetVelocity(AZ::Quaternion::CreateRotationZ(targetHeading).TransformVector(fwd) * speed);
  158. }
  159. }
  160. float NetworkPlayerMovementComponentController::NormalizeHeading(float heading) const
  161. {
  162. // Ensure heading in range [-pi, +pi]
  163. if (heading > AZ::Constants::Pi)
  164. {
  165. return static_cast<float>(heading - AZ::Constants::TwoPi);
  166. }
  167. else if (heading < -AZ::Constants::Pi)
  168. {
  169. return static_cast<float>(heading + AZ::Constants::TwoPi);
  170. }
  171. return heading;
  172. }
  173. void NetworkPlayerMovementComponentController::OnPressed(float value)
  174. {
  175. const StartingPointInput::InputEventNotificationId* inputId = StartingPointInput::InputEventNotificationBus::GetCurrentBusId();
  176. if (inputId == nullptr)
  177. {
  178. return;
  179. }
  180. else if (*inputId == MoveFwdEventId)
  181. {
  182. m_forwardDown = true;
  183. }
  184. else if (*inputId == MoveBackEventId)
  185. {
  186. m_backwardDown = true;
  187. }
  188. else if (*inputId == MoveLeftEventId)
  189. {
  190. m_leftDown = true;
  191. }
  192. else if (*inputId == MoveRightEventId)
  193. {
  194. m_rightDown = true;
  195. }
  196. else if (*inputId == SprintEventId)
  197. {
  198. m_sprinting = true;
  199. }
  200. else if (*inputId == JumpEventId)
  201. {
  202. m_jumping = true;
  203. }
  204. else if (*inputId == CrouchEventId)
  205. {
  206. m_crouching = true;
  207. }
  208. else if (*inputId == LookLeftRightEventId)
  209. {
  210. m_viewYaw = value;
  211. }
  212. else if (*inputId == LookUpDownEventId)
  213. {
  214. m_viewPitch = value;
  215. }
  216. }
  217. void NetworkPlayerMovementComponentController::OnReleased(float value)
  218. {
  219. const StartingPointInput::InputEventNotificationId* inputId = StartingPointInput::InputEventNotificationBus::GetCurrentBusId();
  220. if (inputId == nullptr)
  221. {
  222. return;
  223. }
  224. else if (*inputId == MoveFwdEventId)
  225. {
  226. m_forwardDown = false;
  227. }
  228. else if (*inputId == MoveBackEventId)
  229. {
  230. m_backwardDown = false;
  231. }
  232. else if (*inputId == MoveLeftEventId)
  233. {
  234. m_leftDown = false;
  235. }
  236. else if (*inputId == MoveRightEventId)
  237. {
  238. m_rightDown = false;
  239. }
  240. else if (*inputId == SprintEventId)
  241. {
  242. m_sprinting = false;
  243. }
  244. else if (*inputId == JumpEventId)
  245. {
  246. m_jumping = false;
  247. }
  248. else if (*inputId == CrouchEventId)
  249. {
  250. m_crouching = false;
  251. }
  252. else if (*inputId == LookLeftRightEventId)
  253. {
  254. m_viewYaw = value;
  255. }
  256. else if (*inputId == LookUpDownEventId)
  257. {
  258. m_viewPitch = value;
  259. }
  260. }
  261. void NetworkPlayerMovementComponentController::OnHeld(float value)
  262. {
  263. const StartingPointInput::InputEventNotificationId* inputId = StartingPointInput::InputEventNotificationBus::GetCurrentBusId();
  264. if (inputId == nullptr)
  265. {
  266. return;
  267. }
  268. else if (*inputId == LookLeftRightEventId)
  269. {
  270. m_viewYaw = value;
  271. }
  272. else if (*inputId == LookUpDownEventId)
  273. {
  274. m_viewPitch = value;
  275. }
  276. }
  277. void NetworkPlayerMovementComponentController::UpdateAI()
  278. {
  279. #if AZ_TRAIT_SERVER
  280. float deltaTime = static_cast<float>(m_updateAI.TimeInQueueMs()) / 1000.f;
  281. if (m_networkAiComponentController != nullptr)
  282. {
  283. m_networkAiComponentController->TickMovement(*this, deltaTime);
  284. }
  285. #endif
  286. }
  287. } // namespace ${SanitizedCppName}